From 4a836815f12e8ba717702cc8ed431e1b4f96134c Mon Sep 17 00:00:00 2001
From: riku <risaku@163.com>
Date: 星期五, 25 四月 2025 13:55:34 +0800
Subject: [PATCH] 新增内部线索相关管理逻辑

---
 src/api/clue/clueInternalApi.js                                   |   33 ++
 src/api/clue/clueTaskApi.js                                       |   27 +
 src/model/clueQuestion.js                                         |    2 
 src/api/clue/clueConclusionApi.js                                 |   20 
 src/views/HomePage.vue                                            |    2 
 src/views/overlay-clue/report/ClueReport.vue                      |   12 
 src/views/internal-clue/InternalClueManage.vue                    |  127 +++++++
 src/api/clue/clueQuestionApi.js                                   |   37 ++
 src/components/map/MapSearch.vue                                  |   84 +++-
 src/views/internal-clue/InternalClueLayout.vue                    |   45 ++
 src/views/overlay-clue/report/components/ClueReportQuestion.vue   |   16 
 src/views/overlay-clue/report/components/ClueReportClue.vue       |   25 +
 src/views/overlay-clue/report/components/ClueReportConclusion.vue |   18 
 src/api/index.js                                                  |    2 
 src/components/map/baseMapUtil.js                                 |    8 
 src/views/overlay-clue/report/components/QuestionDetail.vue       |  196 ++++++++++--
 src/views/internal-clue/InternalClueEdit.vue                      |  208 +++++++++++++
 src/components/core/CoreHeader.vue                                |    3 
 src/views/overlay-clue/task/ClueTaskEdit.vue                      |   35 +
 src/api/config.js                                                 |   10 
 src/api/clue/clueApi.js                                           |   16 
 21 files changed, 800 insertions(+), 126 deletions(-)

diff --git a/src/api/clue/clueApi.js b/src/api/clue/clueApi.js
index ce9c458..7087fe9 100644
--- a/src/api/clue/clueApi.js
+++ b/src/api/clue/clueApi.js
@@ -7,14 +7,14 @@
    * @returns
    */
   getClue({ sTime, eTime, pageNum = 1, pageSize = 30 }) {
-    let url = 'clue/fetch?';
-    if (sTime) {
-      url += `sTime=${sTime}&`;
-    }
-    if (eTime) {
-      url += `eTime=${eTime}&`;
-    }
-    return $clue.get(`${url}pageNum=${pageNum}&pageSize=${pageSize}`);
+    return $clue.get(`clue/fetch`, {
+      params: {
+        sTime,
+        eTime,
+        pageNum,
+        pageSize
+      }
+    });
     // .then((res) => res.data);
   },
 
diff --git a/src/api/clue/clueConclusionApi.js b/src/api/clue/clueConclusionApi.js
index cdea07b..481d39c 100644
--- a/src/api/clue/clueConclusionApi.js
+++ b/src/api/clue/clueConclusionApi.js
@@ -5,25 +5,33 @@
    * 鑾峰彇绾跨储缁撹
    * @param {string} clueId 绾跨储id
    */
-  getConclusion(clueId) {
-    return $clue.get(`clue/conclusion/fetch?clueId=${clueId}`).then((res) => res.data);
+  getConclusion(clueId, internal) {
+    return $clue
+      .get(`clue/conclusion/fetch`, {
+        params: { clueId, internal }
+      })
+      .then((res) => res.data);
   },
 
   /**
    * 鎻愪氦绾跨储缁撹
    * @param {object} conclusion 绾跨储
-   * @returns 
+   * @returns
    */
   uploadConclusion(conclusion) {
-    return $clue.post(`clue/conclusion/upload`, conclusion).then((res) => res.data);
+    return $clue
+      .post(`clue/conclusion/upload`, conclusion)
+      .then((res) => res.data);
   },
 
   /**
    * 鎺ㄩ�佺嚎绱㈢粨璁鸿嚦绗笁鏂�
    * @param {Array} conclusionIdList 绾跨储id闆嗗悎
-   * @returns 
+   * @returns
    */
   pushConclusion(conclusionIdList) {
-    return $clue.post(`clue/conclusion/push`, conclusionIdList).then((res) => res.data);
+    return $clue
+      .post(`clue/conclusion/push`, conclusionIdList)
+      .then((res) => res.data);
   }
 };
diff --git a/src/api/clue/clueInternalApi.js b/src/api/clue/clueInternalApi.js
new file mode 100644
index 0000000..7e494de
--- /dev/null
+++ b/src/api/clue/clueInternalApi.js
@@ -0,0 +1,33 @@
+import { $clue } from '../index';
+
+export default {
+  /**
+   * 鏌ヨ绾跨储娓呭崟
+   * @param {object} param0
+   * @returns
+   */
+  getInternalClue({ sTime, eTime, pageNum = 1, pageSize = 30 }) {
+    return $clue.get(`clue/internal/fetch`, {
+      params: {
+        sTime,
+        eTime,
+        pageNum,
+        pageSize
+      }
+    });
+  },
+
+  createInternalClue(clueInternal) {
+    return $clue.put('clue/internal/create', clueInternal);
+  },
+
+  updateInternalClue(clueInternal) {
+    return $clue.post('clue/internal/update', clueInternal);
+  },
+
+  deleteInternalClue(clueInternal) {
+    return $clue.delete('clue/internal/delete', {
+      data: clueInternal
+    });
+  }
+};
diff --git a/src/api/clue/clueQuestionApi.js b/src/api/clue/clueQuestionApi.js
index a5b99a9..7968167 100644
--- a/src/api/clue/clueQuestionApi.js
+++ b/src/api/clue/clueQuestionApi.js
@@ -6,9 +6,11 @@
    * 鑾峰彇宸叉彁浜ょ殑绾跨储闂
    * @param {string} clueId 绾跨储id
    */
-  getQuestion(clueId) {
+  getQuestion(clueId, internal) {
     return $clue
-      .get(`clue/question/fetch?clueId=${clueId}`)
+      .get(`clue/question/fetch`, {
+        params: { clueId, internal }
+      })
       .then((res) => {
         return getClueQuestionList(res.data);
       });
@@ -26,11 +28,34 @@
     files.forEach((e) => {
       formData.append('images', e);
     });
-    return $clue.post(`clue/question/upload`, formData).then((res) => res.data);
+    return $clue
+      .post(`clue/question/upload`, formData)
+      .then((res) => res.data);
+  },
+
+  /**
+   * 淇敼绾跨储闂
+   * @param {object} question 闂鎻忚堪
+   * @param {*} files 闂鍥剧墖
+   * @param {Array} deleteImgUrl 鍒犻櫎鐨勫浘鐗囩浉瀵硅矾寰勶紝鐢�;鍒嗗壊
+   * @returns
+   */
+  updateQuestion(question, files, deleteImgUrl) {
+    const formData = new FormData();
+    formData.append('question', JSON.stringify(question));
+    formData.append('deleteImg', deleteImgUrl);
+    files.forEach((e) => {
+      formData.append('images', e);
+    });
+    return $clue
+      .post(`clue/question/update`, formData)
+      .then((res) => res.data);
   },
 
   deleteQuestion(questionId) {
-    return $clue.delete(`clue/question`, { params: { questionId } }).then((res) => res.data);
+    return $clue
+      .delete(`clue/question`, { params: { questionId } })
+      .then((res) => res.data);
   },
 
   uploadQuestionUrl() {
@@ -43,6 +68,8 @@
    * @returns
    */
   pushQuestion(questionIdList) {
-    return $clue.post(`clue/question/push`, questionIdList).then((res) => res.data);
+    return $clue
+      .post(`clue/question/push`, questionIdList)
+      .then((res) => res.data);
   }
 };
diff --git a/src/api/clue/clueTaskApi.js b/src/api/clue/clueTaskApi.js
index bd52d71..42c151e 100644
--- a/src/api/clue/clueTaskApi.js
+++ b/src/api/clue/clueTaskApi.js
@@ -2,13 +2,21 @@
 
 export default {
   /**
+   * 鍒涘缓鍐呴儴绾跨储浠诲姟
+   * @param {*} clueTask
+   * @returns
+   */
+  createClueTaskInternal(clueTaskInternal) {
+    return $clue.put(`clue/task/create/internal`, clueTaskInternal);
+  },
+
+  /**
    * 鍒涘缓绾跨储浠诲姟
    * @param {*} clueTask
    * @returns
    */
   createClueTask(clueTask) {
-    return $clue
-      .put(`clue/task/create`, clueTask)
+    return $clue.put(`clue/task/create`, clueTask);
   },
 
   /**
@@ -17,8 +25,7 @@
    * @returns
    */
   updateClueTask(clueTask) {
-    return $clue
-      .post(`clue/task/update`, clueTask)
+    return $clue.post(`clue/task/update`, clueTask);
   },
 
   /**
@@ -27,7 +34,15 @@
    * @returns
    */
   fetchClueTask(clueTask) {
-    return $clue
-      .post(`clue/task/fetch`, clueTask)
+    return $clue.post(`clue/task/fetch`, clueTask);
+  },
+
+  /**
+   * 鍒犻櫎绾跨储浠诲姟
+   * @param {*} clueTask
+   * @returns
+   */
+  deleteClueTask(clueTask) {
+    return $clue.post(`clue/task/delete`, clueTask);
   }
 };
diff --git a/src/api/config.js b/src/api/config.js
index e15bd82..3a06f16 100644
--- a/src/api/config.js
+++ b/src/api/config.js
@@ -11,11 +11,6 @@
         // 鍦ㄥ彂閫佽姹備箣鍓�, 娣诲姞璇锋眰澶�
         // config.headers = addHeaders(config.headers);
 
-        console.log('==>璇锋眰寮�濮�');
-        console.log(`${config.baseURL}${config.url}`);
-        if (config.data) {
-          console.log('==>璇锋眰鏁版嵁', config.data);
-        }
         return config;
       },
       function (error) {
@@ -35,6 +30,11 @@
       function (response) {
         // 2xx 鑼冨洿鍐呯殑鐘舵�佺爜閮戒細瑙﹀彂璇ュ嚱鏁般��
         // 瀵瑰搷搴旀暟鎹仛鐐逛粈涔�
+        const config = response.config;
+        console.log('==>璇锋眰寮�濮�', `${config.baseURL}${config.url}`);
+        if (config.data) {
+          console.log('==>璇锋眰鏁版嵁', config.data);
+        }
         console.log(response);
         console.log('==>璇锋眰缁撴潫');
         if (response.status == 200) {
diff --git a/src/api/index.js b/src/api/index.js
index f88ce35..74120e3 100644
--- a/src/api/index.js
+++ b/src/api/index.js
@@ -1,7 +1,7 @@
 import axios from 'axios';
 import { setInterceptors } from "./config";
 
-const debug = true;
+const debug = false;
 
 // let url1 = 'http://47.100.191.150:9031/';
 // let url1_file = 'http://47.100.191.150:9031';
diff --git a/src/components/core/CoreHeader.vue b/src/components/core/CoreHeader.vue
index 7465b24..7294f95 100644
--- a/src/components/core/CoreHeader.vue
+++ b/src/components/core/CoreHeader.vue
@@ -25,7 +25,8 @@
     return {
       radioOptions: [
         { name: '绾跨储绠$悊', label: 0 },
-        { name: '缃戞牸绠$悊', label: 1 }
+        // { name: '缃戞牸绠$悊', label: 1 },
+        { name: '鍐呴儴绾跨储', label: 2 },
       ],
       radio1: 0
     };
diff --git a/src/components/map/MapSearch.vue b/src/components/map/MapSearch.vue
index e397bc5..624f146 100644
--- a/src/components/map/MapSearch.vue
+++ b/src/components/map/MapSearch.vue
@@ -1,9 +1,16 @@
 <template>
-  <el-dialog v-model="dialogShow" width="70%" destroy-on-close>
+  <el-dialog
+    class="dialog"
+    v-model="dialogShow"
+    width="70%"
+    destroy-on-close
+  >
     <template #header>
-      <div> 鍧愭爣鎷惧彇</div>
+      <div>鍧愭爣鎷惧彇</div>
     </template>
-    <div class="fy-tip-red">宸﹂敭鐐瑰嚮鍦板浘閫夊彇鍧愭爣鐐癸紝鎴栬�呮牴鎹叧閿瓧鎼滅储鍦扮偣</div>
+    <div class="fy-tip-red">
+      宸﹂敭鐐瑰嚮鍦板浘閫夊彇鍧愭爣鐐癸紝鎴栬�呮牴鎹叧閿瓧鎼滅储鍦扮偣
+    </div>
     <el-row>
       <el-col :span="10">
         <el-form
@@ -45,11 +52,14 @@
           <span>{{ searchResult.address }}</span>
           <div>
             <span>{{
-              '楂樺痉' + searchResult.lon + ', ' + searchResult.lat
+              '楂樺痉锛�' + searchResult.lon + ', ' + searchResult.lat
             }}</span>
             <el-divider direction="vertical" />
             <span>{{
-              'GPS' + searchResult.gpsLon + ', ' + searchResult.gpsLat
+              'GPS锛�' +
+              searchResult.gpsLon +
+              ', ' +
+              searchResult.gpsLat
             }}</span>
           </div>
         </div>
@@ -94,7 +104,10 @@
     };
   },
   props: {
-    show: Boolean
+    // 瀵硅瘽妗嗘樉绀洪殣钘�
+    show: Boolean,
+    // 榛樿鎼滅储鐐圭粡绾害锛孾lng, lat]
+    defaultCoor: Array
   },
   data() {
     return {
@@ -146,29 +159,21 @@
         geocoder = new AMap.Geocoder({
           city: '涓婃捣' // city 鎸囧畾杩涜缂栫爜鏌ヨ鐨勫煄甯傦紝鏀寔浼犲叆鍩庡競鍚嶃�乤dcode 鍜� citycode
         });
+        if (this.defaultCoor) {
+          const [lng, lat] = baseMapUtil.wgs84togcj02(
+            this.defaultCoor[0],
+            this.defaultCoor[1]
+          );
+          const lnglat = new AMap.LngLat(lng, lat);
+          this.setMarker(lnglat);
+          this.getAddress(lnglat);
+          this.map.setFitView();
+        }
         this.map.on('click', (ev) => {
           // this.formObj.lon = ev.lnglat.getLng();
           // this.formObj.lat = ev.lnglat.getLat();
-          this.map.clearMap();
-          const marker = new AMap.Marker({
-            position: ev.lnglat
-          });
-          this.map.add(marker);
-
-          geocoder.getAddress(ev.lnglat, (status, result) => {
-            if (status === 'complete' && result.info === 'OK') {
-              this.searchResult.address =
-                result.regeocode.formattedAddress;
-              this.searchResult.lon = ev.lnglat.getLng();
-              this.searchResult.lat = ev.lnglat.getLat();
-              const [gpsLon, gpsLat] = baseMapUtil.gcj02towgs84(
-                this.searchResult.lon,
-                this.searchResult.lat
-              );
-              this.searchResult.gpsLon = gpsLon;
-              this.searchResult.gpsLat = gpsLat;
-            }
-          });
+          this.setMarker(ev.lnglat);
+          this.getAddress(ev.lnglat);
         });
       });
       // inited = true;
@@ -199,6 +204,29 @@
         }
       });
     },
+    getAddress(lnglat) {
+      geocoder.getAddress(lnglat, (status, result) => {
+        if (status === 'complete' && result.info === 'OK') {
+          this.searchResult.address =
+            result.regeocode.formattedAddress;
+          this.searchResult.lon = lnglat.getLng();
+          this.searchResult.lat = lnglat.getLat();
+          const [gpsLon, gpsLat] = baseMapUtil.gcj02towgs84(
+            this.searchResult.lon,
+            this.searchResult.lat
+          );
+          this.searchResult.gpsLon = gpsLon;
+          this.searchResult.gpsLat = gpsLat;
+        }
+      });
+    },
+    setMarker(lnglat) {
+      this.map.clearMap();
+      const marker = new AMap.Marker({
+        position: lnglat
+      });
+      this.map.add(marker);
+    },
     submit() {
       this.$emit('onSubmit', this.searchResult);
       this.dialogShow = false;
@@ -218,4 +246,8 @@
   border-radius: var(--el-border-radius-round);
   box-shadow: var(--el-box-shadow);
 }
+
+.dialog {
+  pointer-events: auto;
+}
 </style>
diff --git a/src/components/map/baseMapUtil.js b/src/components/map/baseMapUtil.js
index 02b6601..ce3ad05 100644
--- a/src/components/map/baseMapUtil.js
+++ b/src/components/map/baseMapUtil.js
@@ -129,8 +129,10 @@
   /**
    * 楂樺痉鍦板浘鍧愭爣杞珿PS鍧愭爣绠楁硶
    */
-  gcj02towgs84(lng, lat) {
+  gcj02towgs84(_lng, _lat) {
     // lat = +latlng = +lng
+    const lng = parseFloat(_lng)
+    const lat = parseFloat(_lat)
     if (out_of_china(lng, lat)) {
       return [lng, lat];
     } else {
@@ -158,8 +160,10 @@
    * @param lat
    * @returns {*[]}
    */
-  wgs84togcj02(lng, lat) {
+  wgs84togcj02(_lng, _lat) {
     // lat = +latlng = +lng
+    const lng = parseFloat(_lng)
+    const lat = parseFloat(_lat)
     if (out_of_china(lng, lat)) {
       return [lng, lat];
     } else {
diff --git a/src/model/clueQuestion.js b/src/model/clueQuestion.js
index 5616f09..338523f 100644
--- a/src/model/clueQuestion.js
+++ b/src/model/clueQuestion.js
@@ -1,7 +1,7 @@
 import { $clue } from '@/api/index';
 
 function getClueQuestion(data) {
-  data.cqFilePath = data.cqFilePath.split(';').map((val) => {
+  data.files = data.cqFilePath.split(';').map((val) => {
     return $clue.imgUrl + val;
   });
   return data;
diff --git a/src/views/HomePage.vue b/src/views/HomePage.vue
index 4ede8f0..03c7e04 100644
--- a/src/views/HomePage.vue
+++ b/src/views/HomePage.vue
@@ -5,6 +5,7 @@
     <!-- <router-view> -->
     <ClueLayout v-show="menuIndex == 0"></ClueLayout>
     <GridLayout v-show="menuIndex == 1"></GridLayout>
+    <InternalClueLayout v-show="menuIndex == 2"></InternalClueLayout>
     <!-- </router-view> -->
   </div>
 </template>
@@ -14,6 +15,7 @@
 
 import GridLayout from '@/views/overlay-grid/GridLayout.vue';
 import ClueLayout from '@/views/overlay-clue/ClueLayout.vue';
+import InternalClueLayout from '@/views/internal-clue/InternalClueLayout.vue';
 
 // 椁愬崟绱㈠紩
 const menuIndex = ref(0);
diff --git a/src/views/internal-clue/InternalClueEdit.vue b/src/views/internal-clue/InternalClueEdit.vue
new file mode 100644
index 0000000..99d359f
--- /dev/null
+++ b/src/views/internal-clue/InternalClueEdit.vue
@@ -0,0 +1,208 @@
+<template>
+  <el-dialog
+    style="pointer-events: auto"
+    :model-value="modelValue"
+    @update:modelValue="handleDialogChange"
+    width="50%"
+    :close-on-click-modal="false"
+    :close-on-press-escape="false"
+    destroy-on-close
+  >
+    <template #header>
+      <span> {{ create ? '鍙戝竷鍐呴儴绾跨储' : '鏇存柊鍐呴儴绾跨储' }}</span>
+    </template>
+    <el-form
+      label-width="120px"
+      label-position="right"
+      :rules="rules"
+      :model="formObj"
+      ref="formRef"
+    >
+      <el-form-item label="绾跨储鍚嶇О" prop="cclueName">
+        <el-input
+          v-model="formObj.cclueName"
+          placeholder="璇疯緭鍏ョ嚎绱㈠悕绉�"
+          class="w-200"
+        ></el-input>
+      </el-form-item>
+      <el-form-item label="绾跨储鎻忚堪" prop="cconclusion">
+        <el-input
+          v-model="formObj.cconclusion"
+          type="textarea"
+          placeholder="璇疯緭鍏ョ嚎绱㈡弿杩�"
+        ></el-input>
+      </el-form-item>
+      <el-form-item label="璇︾粏鍦板潃" prop="caddress">
+        <el-input
+          v-model="formObj.caddress"
+          placeholder="璇疯緭鍏ュ湴鍧�鎴栬�呴�氳繃鈥滃潗鏍囨嬀鍙栤�濊嚜鍔ㄨ幏寰�"
+        ></el-input>
+      </el-form-item>
+      <el-form-item label="鍧愭爣" prop="coordinate">
+        <el-input
+          style="width: 300px; margin-right: 8px"
+          v-model="formObj.coordinate"
+          placeholder="缁忕含搴﹀潗鏍囷紝鏍煎紡涓�121.123452,31.231235"
+        ></el-input>
+        <el-button plain type="primary" @click="openMapDialog"
+          >鍧愭爣鎷惧彇</el-button
+        >
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <el-button @click="onCancel">鍙栨秷</el-button>
+      <el-button
+        :disabled="!edit"
+        type="primary"
+        :loading="loading"
+        @click="onSubmit"
+        >纭畾</el-button
+      >
+    </template>
+  </el-dialog>
+  <MapSearch
+    v-model:show="mapDialogShow"
+    @on-submit="selectAddress"
+  ></MapSearch>
+</template>
+<script setup>
+import { ref, reactive, watch, onMounted } from 'vue';
+import { useFormConfirm } from '@/composables/formConfirm';
+import clueInternalApi from '@/api/clue/clueInternalApi';
+
+import MapSearch from '@/components/map/MapSearch.vue';
+
+const props = defineProps({
+  modelValue: Boolean,
+  clueData: Object,
+  create: {
+    type: Boolean,
+    default: true
+  },
+  // 鑷畾涔夊垱寤烘柟娉�
+  onCreate: Function,
+  // 鑷畾涔夋洿鏂版柟娉�
+  onUpdate: Function
+});
+
+const emits = defineEmits(['update:modelValue', 'onSubmit']);
+
+function handleDialogChange(value) {
+  emits('update:modelValue', value);
+}
+
+const { formObj, formRef, edit, onSubmit, onCancel, clear } =
+  useFormConfirm({
+    submit: {
+      do: submit
+    },
+    cancel: {
+      do: cancel
+    }
+  });
+const loading = ref(false);
+// 琛ㄥ崟妫�鏌ヨ鍒�
+const rules = reactive({
+  cclueName: [
+    {
+      required: true,
+      message: '绾跨储鍚嶇О涓嶈兘涓虹┖',
+      trigger: 'blur'
+    }
+  ],
+  caddress: [
+    {
+      required: true,
+      message: '绾跨储鍦板潃涓嶈兘涓虹┖',
+      trigger: 'blur'
+    }
+  ],
+  coordinate: [
+    {
+      required: true,
+      message: '绾跨储瀹氫綅涓嶈兘涓虹┖',
+      trigger: 'blur'
+    }
+  ],
+});
+
+// 瀵硅瘽妗嗙‘璁ゆ搷浣�
+function submit() {
+  const param = getParams();
+  return props.create
+    ? props.onCreate
+      ? props.onCreate(param)
+      : createClue(param)
+    : props.onUpdate
+    ? props.onUpdate(param)
+    : updateClue(param);
+}
+
+// 瀵硅瘽妗嗗彇娑堟搷浣�
+function cancel() {
+  emits('update:modelValue', false);
+}
+
+// 鏂板缓鍐呴儴绾跨储
+function createClue(params) {
+  clueInternalApi
+    .createInternalClue(params)
+    .then(() => {
+      emits('update:modelValue', false);
+      emits('onSubmit');
+    })
+    .finally(() => {
+      loading.value = false;
+    });
+}
+
+// 鏇存柊鍐呴儴绾跨储
+function updateClue(params) {
+  clueInternalApi
+    .updateInternalClue(params)
+    .then(() => {
+      emits('update:modelValue', false);
+      emits('onSubmit');
+    })
+    .finally(() => {
+      loading.value = false;
+    });
+}
+
+// 鑾峰彇绾跨储瀵硅薄鍙傛暟
+function getParams() {
+  const coor = formObj.value.coordinate.split(',');
+  return {
+    cid: formObj.value.cid,
+    cclueName: formObj.value.cclueName,
+    cconclusion: formObj.value.cconclusion,
+    caddress: formObj.value.caddress,
+    clongitude: parseFloat(coor[0]),
+    clatitude: parseFloat(coor[1])
+  };
+}
+
+// 鍒濆鍖栫嚎绱㈣〃鍗曞璞�
+watch(
+  () => [props.modelValue, props.clueData],
+  (nV, oV) => {
+    const [m, d] = nV;
+    if (m) {
+      formObj.value = {};
+      if (d) {
+        formObj.value = d;
+        formObj.value.coordinate = d.cLongitude + ',' + d.cLatitude;
+      }
+    }
+  }
+);
+/*********************************************************** */
+const mapDialogShow = ref(false);
+function openMapDialog() {
+  mapDialogShow.value = true;
+}
+function selectAddress(result) {
+  formObj.value.caddress = result.address;
+  formObj.value.coordinate = result.gpsLon + ',' + result.gpsLat;
+}
+</script>
diff --git a/src/views/internal-clue/InternalClueLayout.vue b/src/views/internal-clue/InternalClueLayout.vue
new file mode 100644
index 0000000..f0c7550
--- /dev/null
+++ b/src/views/internal-clue/InternalClueLayout.vue
@@ -0,0 +1,45 @@
+<template>
+  <el-row class="fy-overlay-container" justify="space-between">
+    <el-col :span="6">
+      <InternalClueManage
+        @itemSelected="selectClue"
+      ></InternalClueManage>
+    </el-col>
+    <el-col :span="6">
+      <ClueReport
+        v-model:show="show"
+        :clueData="selectedClue"
+        @pushed="(e) => (selectedClue.cuploaded = e)"
+        @onClueTaskChange="handleClueTaskChange"
+      ></ClueReport>
+    </el-col>
+  </el-row>
+</template>
+
+<script setup>
+import InternalClueManage from '@/views/internal-clue/InternalClueManage.vue';
+import ClueReport from '@/views/overlay-clue/report/ClueReport.vue';
+import { ref, provide } from 'vue';
+
+// 娉ㄥ叆鍙傛暟
+
+// 琛ㄦ槑褰撳墠鎿嶄綔鐨勬槸鍐呴儴绾跨储
+provide('isInternal', true);
+
+const selectedClue = ref();
+const show = ref(false);
+
+/**
+ * 閫夋嫨绾跨储浜嬩欢
+ */
+const selectClue = function (clue) {
+  show.value = true;
+  selectedClue.value = clue;
+};
+
+function handleClueTaskChange() {
+  selectedClue.value.taskCount = 1;
+}
+</script>
+
+<style scoped></style>
diff --git a/src/views/internal-clue/InternalClueManage.vue b/src/views/internal-clue/InternalClueManage.vue
new file mode 100644
index 0000000..2cfb406
--- /dev/null
+++ b/src/views/internal-clue/InternalClueManage.vue
@@ -0,0 +1,127 @@
+<template>
+  <div class="fy-card">
+    <div class="fy-h1">鍐呴儴绾跨储娓呭崟</div>
+    <div class="fy-flex-row">
+      <span>鏃堕棿</span>
+      <el-date-picker
+        v-model="updateTime"
+        type="datetime"
+        placeholder="閫夋嫨鏃ユ湡鍜屾椂闂�"
+      />
+      <el-button type="primary" @click="getClues">鏌ヨ</el-button>
+      <el-button type="success" @click="clueDialog = true"
+        >鏂板缓</el-button
+      >
+    </div>
+    <el-scrollbar height="70vh" class="p-h-1">
+      <ClueList :dataList="clueList" @itemSelected="selectClue">
+      </ClueList>
+    </el-scrollbar>
+    <el-row justify="space-between" class="p-8">
+      <el-pagination
+        size="small"
+        v-model:current-page="currentPage"
+        v-model:page-size="pageSize"
+        :page-sizes="[10, 20, 50, 100]"
+        :background="true"
+        layout="total, sizes, pager"
+        :total="total"
+      />
+    </el-row>
+  </div>
+  <InternalClueEdit
+    v-model="clueDialog"
+    :create="true"
+    :onCreate="createInternalClue"
+  ></InternalClueEdit>
+  <ClueTaskEdit
+    v-model="clueTaskDialog"
+    :create="true"
+    :onCreate="createInternalTask"
+  ></ClueTaskEdit>
+</template>
+
+<script setup>
+import { ref, onMounted, reactive } from 'vue';
+import moment from 'moment';
+
+import clueInternalApi from '@/api/clue/clueInternalApi';
+import clueTaskApi from '@/api/clue/clueTaskApi';
+import { onMapMounted } from '@/components/map/baseMap';
+
+import ClueList from '@/views/overlay-clue/list/components/ClueList.vue';
+import ClueTaskEdit from '@/views/overlay-clue/task/ClueTaskEdit.vue';
+import InternalClueEdit from '@/views/internal-clue/InternalClueEdit.vue';
+
+const emits = defineEmits('itemSelected');
+
+// 涓嬪彂鏃堕棿锛堟瘡娆℃煡璇㈠ぇ浜庢鏃堕棿鐨勬暟鎹級
+const updateTime = ref();
+// 绾跨储娓呭崟
+const clueList = ref([]);
+const currentPage = ref(1);
+const pageSize = ref(100);
+const total = ref(0);
+
+/**
+ * 鏌ヨ宸蹭笅鍙戠殑绾跨储娓呭崟
+ */
+const getClues = function () {
+  let sTime;
+  let eTime;
+  if (updateTime.value) {
+    const now = moment(updateTime.value);
+    sTime = now.format('YYYY-MM-DD HH:mm:ss');
+    eTime = now.add(1, 'month').format('YYYY-MM-DD HH:mm:ss');
+  }
+  onMapMounted(() => {
+    clueInternalApi
+      .getInternalClue({
+        sTime,
+        eTime,
+        pageNum: currentPage.value,
+        pageSize: pageSize.value
+      })
+      .then((res) => {
+        total.value = res.head.totalCount;
+        clueList.value = res.data;
+      });
+  });
+};
+
+/**
+ * 閫夋嫨绾跨储浜嬩欢
+ */
+const selectClue = function (clue) {
+  emits('itemSelected', clue);
+};
+
+onMounted(() => {
+  getClues();
+});
+
+/************************************************************** */
+const clueData = ref();
+const clueDialog = ref(false);
+const clueTaskDialog = ref(false);
+
+function createInternalClue(clue) {
+  clueData.value = clue;
+  clueDialog.value = false;
+  clueTaskDialog.value = true;
+}
+function createInternalTask(clueTask) {
+  clueTaskApi
+    .createClueTaskInternal({
+      clueTask: clueTask,
+      clueInternal: clueData.value
+    })
+    .then((res) => {
+      if (res.success) {
+        clueTaskDialog.value = false;
+        getClues();
+      }
+    });
+}
+</script>
+<style scoped></style>
diff --git a/src/views/overlay-clue/report/ClueReport.vue b/src/views/overlay-clue/report/ClueReport.vue
index 3f9ed43..d342985 100644
--- a/src/views/overlay-clue/report/ClueReport.vue
+++ b/src/views/overlay-clue/report/ClueReport.vue
@@ -2,6 +2,7 @@
   <!-- 娓呭崟璇︽儏 -->
   <CloseButton v-show="show" @close="closeEdit">
     <el-button
+      v-if="!isInternal"
       class="push-btn"
       :type="clueData.cuploaded ? 'success' : 'danger'"
       @click="pushCheck"
@@ -76,6 +77,12 @@
 import clueTaskApi from '@/api/clue/clueTaskApi';
 
 export default {
+  inject: {
+    // 鏄惁鏄唴閮ㄧ嚎绱㈢浉鍏虫搷浣�
+    isInternal: {
+      default: false
+    }
+  },
   components: {
     ClueReportClue,
     ClueReportConclusion,
@@ -127,7 +134,10 @@
 
     getClueTask() {
       clueTaskApi
-        .fetchClueTask({ clueId: this.clueData.cid })
+        .fetchClueTask({
+          clueId: this.clueData.cid,
+          internalTask: this.isInternal
+        })
         .then((res) => {
           this.isCreateMode = res.data.length == 0;
           if (res.data.length > 0) {
diff --git a/src/views/overlay-clue/report/components/ClueReportClue.vue b/src/views/overlay-clue/report/components/ClueReportClue.vue
index 6010893..0e83ad2 100644
--- a/src/views/overlay-clue/report/components/ClueReportClue.vue
+++ b/src/views/overlay-clue/report/components/ClueReportClue.vue
@@ -2,7 +2,12 @@
   <!-- 娓呭崟璇︽儏 -->
   <DescriptionsList title="绾跨储娓呭崟璇︽儏">
     <template #extra>
-      <el-button type="primary" text size="small" @click="openPDF"
+      <el-button
+        v-if="!isInternal"
+        type="primary"
+        text
+        size="small"
+        @click="openPDF"
         >鏌ョ湅PDF</el-button
       >
     </template>
@@ -11,8 +16,14 @@
       label="绾跨储鍚嶇О"
       :content="clue.cclueName"
     />
-    <DescriptionsListItem label="鍒涘缓鏃堕棿" :content="$tf(clue.ccreateTime)" />
-    <DescriptionsListItem label="涓嬪彂鏃堕棿" :content="$tf(clue.creleaseTime)" />
+    <DescriptionsListItem
+      label="鍒涘缓鏃堕棿"
+      :content="$tf(clue.ccreateTime)"
+    />
+    <DescriptionsListItem
+      label="涓嬪彂鏃堕棿"
+      :content="$tf(clue.creleaseTime)"
+    />
     <DescriptionsListItem
       label="鎶ヨ绔欑偣"
       :content="clue.csiteName"
@@ -36,6 +47,12 @@
 import clueApi from '@/api/clue/clueApi';
 
 export default {
+  inject: {
+    // 鏄惁鏄唴閮ㄧ嚎绱㈢浉鍏虫搷浣�
+    isInternal: {
+      default: false
+    }
+  },
   props: {
     clue: Object
   },
@@ -46,6 +63,6 @@
         '_blank'
       );
     }
-  },
+  }
 };
 </script>
diff --git a/src/views/overlay-clue/report/components/ClueReportConclusion.vue b/src/views/overlay-clue/report/components/ClueReportConclusion.vue
index f62719f..2e21ce5 100644
--- a/src/views/overlay-clue/report/components/ClueReportConclusion.vue
+++ b/src/views/overlay-clue/report/components/ClueReportConclusion.vue
@@ -74,10 +74,13 @@
 </template>
 
 <script setup>
-import { reactive, ref, watch, computed } from 'vue';
+import { reactive, ref, watch, computed, inject } from 'vue';
 import { useCloned } from '@vueuse/core';
 import { useFormConfirm } from '@/composables/formConfirm';
 import clueConclusionApi from '@/api/clue/clueConclusionApi';
+
+// 鍐冲畾褰撳墠鏄惁鏄唴閮ㄧ嚎绱㈢浉鍏虫搷浣�
+const isInternal = inject('isInternal', false);
 
 const props = defineProps({
   clueId: Number
@@ -137,6 +140,7 @@
 
 function submit() {
   formObj.value.cid = props.clueId;
+  formObj.value.ccInternal = isInternal;
   return uploadConclusion();
 }
 function cancel() {
@@ -164,11 +168,13 @@
  * 鑾峰彇绾跨储缁撹
  */
 function getConclusion() {
-  clueConclusionApi.getConclusion(props.clueId).then((res) => {
-    conclusion.value = res;
-    formObj.value = res == null ? {} : res;
-    // formObj.value = useCloned(res, { manual: true });
-  });
+  clueConclusionApi
+    .getConclusion(props.clueId, isInternal)
+    .then((res) => {
+      conclusion.value = res;
+      formObj.value = res == null ? {} : res;
+      // formObj.value = useCloned(res, { manual: true });
+    });
 }
 </script>
 <style scoped></style>
diff --git a/src/views/overlay-clue/report/components/ClueReportQuestion.vue b/src/views/overlay-clue/report/components/ClueReportQuestion.vue
index ba7598f..35740f2 100644
--- a/src/views/overlay-clue/report/components/ClueReportQuestion.vue
+++ b/src/views/overlay-clue/report/components/ClueReportQuestion.vue
@@ -6,10 +6,10 @@
         <template #extra>
           <div>
             <el-button
+              v-if="!clueData.cuploaded"
               type="danger"
               size="small"
               icon="Delete"
-              :disabled="clueData.cuploaded"
               @click="deleteQuestion(item)"
             ></el-button>
             <el-button
@@ -55,6 +55,7 @@
   </div>
   <QuestionDetail
     :clueData="clueData"
+    :uploaded="clueData.cuploaded"
     v-model:show="dialogShow"
     :question="selectedQuestion"
     @on-submit="getQuestion"
@@ -62,13 +63,16 @@
 </template>
 
 <script setup>
-import { ref, watch, computed } from 'vue';
+import { ref, watch, computed, inject } from 'vue';
 import clueQuestionApi from '@/api/clue/clueQuestionApi';
 import QuestionDetail from './QuestionDetail.vue';
 import {
   useMessageBoxTip,
   useMessageBox
 } from '@/composables/messageBox';
+
+// 鍐冲畾褰撳墠鏄惁鏄唴閮ㄧ嚎绱㈢浉鍏虫搷浣�
+const isInternal = inject('isInternal', false);
 
 const props = defineProps({
   // clueId: Number,
@@ -129,9 +133,11 @@
  * 鑾峰彇绾跨储缁撹
  */
 function getQuestion() {
-  clueQuestionApi.getQuestion(props.clueData.cid).then((res) => {
-    questionList.value = res;
-  });
+  clueQuestionApi
+    .getQuestion(props.clueData.cid, isInternal)
+    .then((res) => {
+      questionList.value = res;
+    });
 }
 
 function pushQuestion(item) {
diff --git a/src/views/overlay-clue/report/components/QuestionDetail.vue b/src/views/overlay-clue/report/components/QuestionDetail.vue
index f0f6603..7352c04 100644
--- a/src/views/overlay-clue/report/components/QuestionDetail.vue
+++ b/src/views/overlay-clue/report/components/QuestionDetail.vue
@@ -7,7 +7,11 @@
     destroy-on-close
   >
     <template #header>
-      <span> 娣诲姞闂</span>
+      <span>
+        {{
+          uploaded ? '闂璇︽儏' : createMode ? '娣诲姞闂' : '淇敼闂'
+        }}</span
+      >
     </template>
     <el-form
       label-width="90px"
@@ -18,19 +22,25 @@
     >
       <el-form-item label="闂鍚嶇О" prop="cqName">
         <el-input
+          :disabled="uploaded"
           v-model="formObj.cqName"
           placeholder="璇疯緭鍏ラ棶棰樺悕绉�"
         ></el-input>
       </el-form-item>
       <el-form-item label="闂鎻忚堪" prop="cqDescription">
         <el-input
+          :disabled="uploaded"
           v-model="formObj.cqDescription"
           type="textarea"
           placeholder="璇疯緭鍏ラ棶棰樻弿杩�"
         ></el-input>
       </el-form-item>
       <el-form-item label="鎵�鍦ㄨ闀�" prop="cqStreet">
-        <el-select v-model="formObj.cqStreet" placeholder="鎵�鍦ㄨ闀�">
+        <el-select
+          v-model="formObj.cqStreet"
+          placeholder="鎵�鍦ㄨ闀�"
+          :disabled="uploaded"
+        >
           <el-option
             v-for="s in streets"
             :key="s.value"
@@ -41,22 +51,29 @@
       </el-form-item>
       <el-form-item label="璇︾粏鍦板潃" prop="cqAddress">
         <el-input
+          :disabled="uploaded"
           v-model="formObj.cqAddress"
           placeholder="璇疯緭鍏ュ湴鍧�鎴栬�呴�氳繃鈥滃潗鏍囨嬀鍙栤�濊嚜鍔ㄨ幏寰�"
         ></el-input>
       </el-form-item>
       <el-form-item label="鍧愭爣" prop="coordinate">
         <el-input
+          :disabled="uploaded"
           style="width: 300px; margin-right: 8px"
           v-model="formObj.coordinate"
           placeholder="缁忕含搴﹀潗鏍囷紝鏍煎紡涓�121.123452,31.231235"
         ></el-input>
-        <el-button plain type="primary" @click="openMapDialog"
+        <el-button
+          :disabled="uploaded"
+          plain
+          type="primary"
+          @click="openMapDialog"
           >鍧愭爣鎷惧彇</el-button
         >
       </el-form-item>
       <el-form-item label="闂鍥剧墖" prop="files">
         <el-upload
+          :class="uploadableClz"
           ref="uploadRef"
           :file-list="fileList"
           action=""
@@ -64,16 +81,49 @@
           list-type="picture-card"
           name="images"
           accept="image/png, image/jpeg"
-          :limit="3"
+          :limit="maxImageCount"
           multiple
           :on-preview="handleFilePreview"
           :on-remove="handleFileRemove"
           :on-change="handleFileChange"
         >
           <el-icon><Plus /></el-icon>
+          <template #file="{ file }">
+            <div>
+              <img
+                class="el-upload-list__item-thumbnail"
+                :src="file.url"
+                alt=""
+              />
+              <span class="el-upload-list__item-actions">
+                <span
+                  class="el-upload-list__item-preview"
+                  @click="handleFilePreview(file)"
+                >
+                  <el-icon><zoom-in /></el-icon>
+                </span>
+                <!-- <span
+                  v-if="!disabled"
+                  class="el-upload-list__item-delete"
+                  @click="handleDownload(file)"
+                >
+                  <el-icon><Download /></el-icon>
+                </span> -->
+                <span
+                  v-if="!uploaded"
+                  class="el-upload-list__item-delete"
+                  @click="handleFileRemove(file)"
+                >
+                  <el-icon><Delete /></el-icon>
+                </span>
+              </span>
+            </div>
+          </template>
           <template #tip>
             <div class="el-upload__tip">
-              璇烽�夋嫨灏忎簬500kb鐨刯pg/png鍥剧墖锛屾渶澶�3寮�
+              {{
+                `璇烽�夋嫨灏忎簬500kb鐨刯pg/png鍥剧墖锛屾渶澶�${maxImageCount}寮燻
+              }}
             </div>
           </template>
         </el-upload>
@@ -99,47 +149,78 @@
   ></el-image-viewer>
   <MapSearch
     v-model:show="mapDialogShow"
+    :defaultCoor="
+      formObj.coordinate
+        ? formObj.coordinate.split(',')
+        : undefined
+    "
     @on-submit="selectAddress"
   ></MapSearch>
 </template>
 
 <script setup>
-import { reactive, ref, watch, computed } from 'vue';
+import { reactive, ref, watch, computed, inject } from 'vue';
+import { ElMessage } from 'element-plus';
 import { useFormConfirm } from '@/composables/formConfirm';
 import { streets } from '@/constant/street';
 import clueQuestionApi from '@/api/clue/clueQuestionApi';
+import { $clue } from '@/api/index';
 import MapSearch from '@/components/map/MapSearch.vue';
 
+// 鍐冲畾褰撳墠鏄惁鏄唴閮ㄧ嚎绱㈢浉鍏虫搷浣�
+const isInternal = inject('isInternal', false);
+
 const props = defineProps({
-  clueId: Number,
+  // 搴旀�ョ嚎绱㈠璞�
   clueData: {
     type: Object,
     default: () => {
       return {};
     }
   },
+  // 瀵硅瘽妗嗘樉绀烘帶鍒�
   show: Boolean,
+  // 绾跨储闂瀵硅薄
   question: Object,
-  create: {
+  // 闂鏄惁宸蹭笂浼�
+  uploaded: {
     type: Boolean,
-    default: true
+    default: false
+  },
+  maxImageCount: {
+    type: Number,
+    default: 3
   }
 });
 
 const emit = defineEmits(['update:show', 'onSubmit', 'onClose']);
+
+// 鍒涘缓鎴栨槸淇敼妯″紡
+const createMode = ref(true);
 
 // 涓婃姤寮瑰嚭妗�
 const dialogShow = ref(false);
 const mapDialogShow = ref(false);
 const uploadRef = ref();
 const fileList = ref([]);
+// 鏇存柊妯″紡涓嬶紝璁板綍琚垹闄ょ殑鍘熸湁鍥剧墖
+let deletedFileList = [];
+// 鍐冲畾鏄惁鑳戒笂浼犲浘鐗�
+const uploadableClz = computed(() => {
+  return props.uploaded ||
+    (fileList.value && fileList.value.length >= props.maxImageCount)
+    ? 'question-not-upload'
+    : '';
+});
 
 const previewShow = ref(false);
 const initialIndex = ref(0);
 const urlList = computed(() =>
-  fileList.value.map((value) => {
-    return value.url;
-  })
+  fileList.value
+    ? fileList.value.map((value) => {
+        return value.url;
+      })
+    : []
 );
 
 function handleFilePreview(file) {
@@ -151,12 +232,22 @@
   previewShow.value = false;
 }
 
-function handleFileRemove(file, fileList) {
-  formObj.value.files = fileList;
+function handleFileRemove(file, files) {
+  if (!createMode.value) {
+    if (file.url.indexOf($clue.imgUrl) != -1) {
+      const originUrl = file.url.replace($clue.imgUrl, '');
+      deletedFileList.push(originUrl);
+    }
+  }
+  const index = fileList.value.indexOf(file);
+  fileList.value.splice(index, 1);
+  // fileList.value = fileList;
+  edit.value = true;
 }
 
-function handleFileChange(file, fileList) {
-  formObj.value.files = fileList;
+function handleFileChange(file, files) {
+  fileList.value = files;
+  edit.value = true;
 }
 
 const { formObj, formRef, edit, onSubmit, onCancel, clear } =
@@ -230,23 +321,38 @@
 });
 
 function submit() {
+  if (!fileList.value || fileList.value.length == 0) {
+    ElMessage({
+      message: '鑷冲皯涓婁紶涓�寮犲浘鐗�',
+      type: 'error'
+    });
+    return;
+  }
   const coor = formObj.value.coordinate.split(',');
   const q = {
-    cid: parseInt(props.clueData.cid),
-    cqName: formObj.value.cqName,
-    cqDescription: formObj.value.cqDescription,
-    cqStreet: formObj.value.cqStreet,
-    cqAddress: formObj.value.cqAddress,
+    ...formObj.value,
+    // cqId: formObj.value.cqId,
+    cId: parseInt(props.clueData.cid),
+    // cqName: formObj.value.cqName,
+    // cqDescription: formObj.value.cqDescription,
+    // cqStreet: formObj.value.cqStreet,
+    // cqAddress: formObj.value.cqAddress,
     cqLongitude: parseFloat(coor[0]),
-    cqLatitude: parseFloat(coor[1])
+    cqLatitude: parseFloat(coor[1]),
+    cqInternal: isInternal
+    // cqFilePath: formObj.value.cqFilePath
   };
   const files = [];
-  if (formObj.value.files) {
-    formObj.value.files.forEach((f) => {
-      files.push(f.raw);
+  if (fileList.value) {
+    fileList.value.forEach((f) => {
+      if (f.url.indexOf($clue.imgUrl) == -1) {
+        files.push(f.raw);
+      }
     });
   }
-  return props.create ? uploadQuestion(q, files) : updateQuestion(q, );
+  return createMode.value
+    ? uploadQuestion(q, files)
+    : updateQuestion(q, files);
 }
 
 function cancel() {
@@ -268,12 +374,11 @@
  */
 function uploadQuestion(question, files) {
   loading.value = true;
-
   return clueQuestionApi
     .uploadQuestion(question, files)
     .then(() => {
       dialogShow.value = false;
-      clear();
+      // clear();
       uploadRef.value.clearFiles();
       emit('onSubmit');
     })
@@ -282,19 +387,30 @@
     });
 }
 
-function updateQuestion(question, newFiles, deleteFiles) {
-  
+function updateQuestion(question, newFiles) {
+  loading.value = true;
+  const deleteImgUrl = deletedFileList.join(';');
+  return clueQuestionApi
+    .updateQuestion(question, newFiles, deleteImgUrl)
+    .then(() => {
+      dialogShow.value = false;
+      // clear();
+      uploadRef.value.clearFiles();
+      emit('onSubmit');
+    })
+    .finally(() => {
+      loading.value = false;
+    });
 }
 
 function parseFormObj(question) {
   question.coordinate =
     question.cqLongitude + ',' + question.cqLatitude;
-  fileList.value = [];
-  question.cqFilePath.forEach((f, index) => {
-    fileList.value.push({
+  fileList.value = question.files.map((f, index) => {
+    return {
       name: `${index}`,
       url: f
-    });
+    };
   });
   return { ...question };
 }
@@ -305,16 +421,28 @@
     dialogShow.value = val[0];
     if (val[0]) {
       fileList.value = [];
+      deletedFileList = [];
       if (val[1]) {
+        createMode.value = false;
         formObj.value = parseFormObj(val[1]);
       } else {
+        createMode.value = true;
         formObj.value = {};
       }
+      // edit.value = false
     }
   }
 );
 
 watch(dialogShow, (val) => {
+  if (!val) {
+    clear();
+  }
   emit('update:show', val);
 });
 </script>
+<style scoped>
+:deep(.question-not-upload .el-upload-list > .el-upload) {
+  display: none;
+}
+</style>
diff --git a/src/views/overlay-clue/task/ClueTaskEdit.vue b/src/views/overlay-clue/task/ClueTaskEdit.vue
index 26aca1b..ee4a4dc 100644
--- a/src/views/overlay-clue/task/ClueTaskEdit.vue
+++ b/src/views/overlay-clue/task/ClueTaskEdit.vue
@@ -85,17 +85,16 @@
 
 const props = defineProps({
   modelValue: Boolean,
-  clueData: {
-    type: Object,
-    default: () => {
-      return {};
-    }
-  },
+  clueData: Object,
   clueTask: Object,
   create: {
     type: Boolean,
     default: true
-  }
+  },
+  // 鑷畾涔夊垱寤烘柟娉�
+  onCreate: Function,
+  // 鑷畾涔夋洿鏂版柟娉�
+  onUpdate: Function
 });
 
 const emits = defineEmits(['update:modelValue', 'onSubmit']);
@@ -116,13 +115,13 @@
 const loading = ref(false);
 // 琛ㄥ崟妫�鏌ヨ鍒�
 const rules = reactive({
-  clueId: [
-    {
-      required: true,
-      message: '绾跨储缂栧彿涓嶈兘涓虹┖',
-      trigger: 'blur'
-    }
-  ],
+  // clueId: [
+  //   {
+  //     required: true,
+  //     message: '绾跨储缂栧彿涓嶈兘涓虹┖',
+  //     trigger: 'blur'
+  //   }
+  // ],
   taskTime: [
     {
       required: true,
@@ -155,7 +154,13 @@
 
 function submit() {
   const param = getParams();
-  return props.create ? createClueTask(param) : updateClueTask(param);
+  return props.create
+    ? props.onCreate
+      ? props.onCreate(param)
+      : createClueTask(param)
+    : props.onUpdate
+    ? props.onUpdate(param)
+    : updateClueTask(param);
 }
 
 function cancel() {

--
Gitblit v1.9.3