From 2d3d56ff801b73afdb779267004d740f9beafe57 Mon Sep 17 00:00:00 2001 From: riku <risaku@163.com> Date: 星期二, 31 十月 2023 16:09:44 +0800 Subject: [PATCH] 2023.10.31 --- src/assets/shortcut.css | 16 src/components/button/CloseButton.vue | 36 + src/model/clueQuestion.js | 2 src/api/clue/clueConclusionApi.js | 2 src/components.d.ts | 10 src/components/search-option/OptionTime.vue | 4 src/views/HomePage.vue | 12 src/views/overlay-clue/report/ClueReport.vue | 107 +++ src/composables/formConfirm.js | 21 src/views/overlay-clue/list/ClueManage.vue | 80 ++ src/views/overlay-grid/components/ListGridDetail.vue | 6 src/api/clue/clueQuestionApi.js | 2 src/views/overlay-clue/report/components/ClueReportClue.vue | 51 + src/api/index.js | 33 src/api/grid/gridInfoApi.js | 31 src/components/map/baseMapUtil.js | 55 + src/assets/text.css | 4 src/views/overlay-grid/components/GridCreate.vue | 96 +- vite.config.js | 3 src/api/config.js | 82 ++ src/api/clue/clueApi.js | 30 src/views/overlay-clue/list/components/ClueList.vue | 138 ++++ src/assets/main.css | 28 src/views/overlay-grid/components/OptionGridRecord.vue | 48 src/model/gridRecord.js | 28 src/components/list/DescriptionsList.vue | 31 src/views/overlay-grid/components/SchemeCreate.vue | 101 ++ src/components/list/DescriptionsListItem.vue | 36 + src/components/map/mapGrid.js | 6 src/utils/textFormat.js | 19 src/views/overlay-clue/report/components/ClueReportQuestion.vue | 76 - /dev/null | 104 --- src/stores/grid.js | 37 src/views/overlay-clue/report/components/ClueReportConclusion.vue | 58 src/assets/base.css | 70 - src/main.js | 5 src/views/overlay-grid/components/GridEditing.vue | 94 ++ src/composables/messageBox.js | 48 src/views/overlay-clue/report/components/QuestionDetail.vue | 84 + src/components/core/CoreHeader.vue | 44 + src/api/grid/gridSchemeApi.js | 18 src/assets/layout.css | 56 + src/views/overlay-grid/GridLayout.vue | 99 +- src/views/overlay-clue/ClueLayout.vue | 115 -- 44 files changed, 1,432 insertions(+), 594 deletions(-) diff --git a/src/api/clue/clueApi.js b/src/api/clue/clueApi.js index 0ce8f48..82e565a 100644 --- a/src/api/clue/clueApi.js +++ b/src/api/clue/clueApi.js @@ -1,23 +1,43 @@ -import { $clue } from './index'; +import { $clue } from '../index'; export default { /** * 鏌ヨ绾跨储娓呭崟 - * @param {object} param0 - * @returns + * @param {object} param0 + * @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( - `clue/fetch?sTime=${sTime}&eTime=${eTime}&pageNum=${pageNum}&pageSize=${pageSize}` + `${url}pageNum=${pageNum}&pageSize=${pageSize}` ); }, /** * 浠庣涓夋柟杩滅▼鎷夊彇绾跨储娓呭崟 * @param {string} updateTime 鏇存柊鏃堕棿锛岃幏鍙栬鏃堕棿涔嬪悗鐨勭嚎绱� - * @returns + * @returns */ fetchRemoteClue(updateTime) { return $clue.get(`clue/fetch/remote?updateTime=${updateTime}`); + }, + + fetchRemoteClueFileUrl(clueId) { + return `${$clue.defaults.baseURL}clue/fetch/remote/file?clueId=${clueId}`; + }, + + /** + * 鎺ㄩ�佺嚎绱㈢殑缁撹涓庨棶棰� + * @param {string} clueId + * @returns + */ + pushClue(clueId) { + return $clue.post(`clue/push?clueId=${clueId}`); } }; diff --git a/src/api/clue/clueConclusionApi.js b/src/api/clue/clueConclusionApi.js index ede0d44..9a4a076 100644 --- a/src/api/clue/clueConclusionApi.js +++ b/src/api/clue/clueConclusionApi.js @@ -1,4 +1,4 @@ -import { $clue } from './index'; +import { $clue } from '../index'; export default { /** diff --git a/src/api/clue/clueQuestionApi.js b/src/api/clue/clueQuestionApi.js index 4f820d5..8d04cf6 100644 --- a/src/api/clue/clueQuestionApi.js +++ b/src/api/clue/clueQuestionApi.js @@ -1,4 +1,4 @@ -import { $clue } from './index'; +import { $clue } from '../index'; import { getClueQuestionList } from '@/model/clueQuestion'; export default { diff --git a/src/api/clue/index.js b/src/api/clue/index.js deleted file mode 100644 index 678789c..0000000 --- a/src/api/clue/index.js +++ /dev/null @@ -1,105 +0,0 @@ -import axios from 'axios'; -import md5 from 'md5'; -import { ElMessage } from 'element-plus'; - -const url = 'http://47.100.191.150:9030/'; -// const url = 'http://192.168.1.9:8080/'; -const imgUrl = url + 'images/'; - -//椋炵窘鐩戠 -const $clue = axios.create({ - baseURL: url, - timeout: 10000 - // headers: addHeaders() -}); -// console.log($clue); - -function getHeaders() { - const token = 'e6dc8bb9e1ff0ce973fb92b4af2e4c3f'; - - const date = new Date(); - const timestamp = parseInt(date.getTime() / 1000) - 200; - - const sign = md5(timestamp + token); - - // headers['JA-TIMESTAMP'] = timestamp; - // headers['JA-SIGN'] = sign; - // headers['JA-TOKEN'] = token; - - return { - 'JA-TIMESTAMP': timestamp, - 'JA-SIGN': sign, - 'JA-TOKEN': token - }; -} - -//娣诲姞鎷︽埅鍣� -[$clue].forEach((i) => { - // 娣诲姞璇锋眰鎷︽埅鍣� - i.interceptors.request.use( - function (config) { - // 鍦ㄥ彂閫佽姹備箣鍓�, 娣诲姞璇锋眰澶� - // config.headers = addHeaders(config.headers); - - console.log('==>璇锋眰寮�濮�'); - console.log(`${config.baseURL}${config.url}`); - if (config.data) { - console.log('==>璇锋眰鏁版嵁', config.data); - } - return config; - }, - function (error) { - // 瀵硅姹傞敊璇仛浜涗粈涔� - console.log('==>璇锋眰寮�濮�'); - console.log(error); - ElMessage({ - message: error, - type: 'error' - }); - return Promise.reject(error); - } - ); - - // 娣诲姞鍝嶅簲鎷︽埅鍣� - i.interceptors.response.use( - function (response) { - // 2xx 鑼冨洿鍐呯殑鐘舵�佺爜閮戒細瑙﹀彂璇ュ嚱鏁般�� - // 瀵瑰搷搴旀暟鎹仛鐐逛粈涔� - console.log(response); - console.log('==>璇锋眰缁撴潫'); - if (response.status == 200) { - if ( - response.data.success != undefined && - response.data.success != null - ) { - if (response.data.success == true) { - return response.data.data; - } else { - ElMessage({ - message: response.data.message, - type: 'error' - }); - return Promise.reject(response.data.message); - } - } else { - return response; - } - } else { - return Promise.reject(response); - } - }, - function (error) { - // 瓒呭嚭 2xx 鑼冨洿鐨勭姸鎬佺爜閮戒細瑙﹀彂璇ュ嚱鏁般�� - // 瀵瑰搷搴旈敊璇仛鐐逛粈涔� - console.log(error); - console.log('==>璇锋眰缁撴潫'); - ElMessage({ - message: error, - type: 'error' - }); - return Promise.reject(error); - } - ); -}); - -export { $clue, imgUrl }; diff --git a/src/api/config.js b/src/api/config.js new file mode 100644 index 0000000..c322f3f --- /dev/null +++ b/src/api/config.js @@ -0,0 +1,82 @@ +import { ElMessage } from 'element-plus'; + +/** + * 璁剧疆缃戣矾璇锋眰鐩戝惉 + */ +function setInterceptors(...instance) { + instance.forEach((i) => { + // 娣诲姞璇锋眰鎷︽埅鍣� + i.interceptors.request.use( + function (config) { + // 鍦ㄥ彂閫佽姹備箣鍓�, 娣诲姞璇锋眰澶� + // config.headers = addHeaders(config.headers); + + console.log('==>璇锋眰寮�濮�'); + console.log(`${config.baseURL}${config.url}`); + if (config.data) { + console.log('==>璇锋眰鏁版嵁', config.data); + } + return config; + }, + function (error) { + // 瀵硅姹傞敊璇仛浜涗粈涔� + console.log('==>璇锋眰寮�濮�'); + console.log(error); + ElMessage({ + message: error, + type: 'error' + }); + return Promise.reject(error); + } + ); + + // 娣诲姞鍝嶅簲鎷︽埅鍣� + i.interceptors.response.use( + function (response) { + // 2xx 鑼冨洿鍐呯殑鐘舵�佺爜閮戒細瑙﹀彂璇ュ嚱鏁般�� + // 瀵瑰搷搴旀暟鎹仛鐐逛粈涔� + console.log(response); + console.log('==>璇锋眰缁撴潫'); + if (response.status == 200) { + if ( + response.data.success != undefined && + response.data.success != null + ) { + if (response.data.success == true) { + // if (response.data.message && response.data.message != '') { + // ElMessage({ + // message: response.data.message, + // type: 'success' + // }); + // } + return response.data.data; + } else { + ElMessage({ + message: response.data.message, + type: 'error' + }); + return Promise.reject(response.data.message); + } + } else { + return response; + } + } else { + return Promise.reject(response); + } + }, + function (error) { + // 瓒呭嚭 2xx 鑼冨洿鐨勭姸鎬佺爜閮戒細瑙﹀彂璇ュ嚱鏁般�� + // 瀵瑰搷搴旈敊璇仛鐐逛粈涔� + console.log(error); + console.log('==>璇锋眰缁撴潫'); + ElMessage({ + message: error, + type: 'error' + }); + return Promise.reject(error); + } + ); + }); +} + +export { setInterceptors }; diff --git a/src/api/grid/gridInfoApi.js b/src/api/grid/gridInfoApi.js new file mode 100644 index 0000000..824675e --- /dev/null +++ b/src/api/grid/gridInfoApi.js @@ -0,0 +1,31 @@ +import { $clue } from '../index'; +import { getGridRecord, getGridRecordList } from '@/model/gridRecord'; + +export default { + /** + * 鑾峰彇鏂规缃戞牸淇℃伅 + */ + fetchGridList(schemeId) { + return $clue.get(`grid/info/fetch?id=${schemeId}`).then((res) => { + return getGridRecordList(res); + }); + }, + + /** + * 鏂板缓缃戞牸 + * @param {Object} grid + */ + createGrid(gridInfo) { + return $clue.post(`grid/info/create`, gridInfo).then((res) => { + return getGridRecord(res); + }); + }, + + /** + * 鏇存柊缃戞牸 + * @param {Object} gridInfo + */ + updateGrid(gridInfo) { + return $clue.post(`grid/info/update`, gridInfo) + } +}; diff --git a/src/api/grid/gridSchemeApi.js b/src/api/grid/gridSchemeApi.js new file mode 100644 index 0000000..eaee15d --- /dev/null +++ b/src/api/grid/gridSchemeApi.js @@ -0,0 +1,18 @@ +import { $clue } from '../index'; + +export default { + /** + * 鑾峰彇鍏ㄩ儴缃戞牸鍖栬鍒掓柟妗� + */ + fetchAllSchemes() { + return $clue.get(`grid/scheme/fetch`); + }, + + /** + * 鏂板缓缃戞牸鏂规 + * @param {Object} scheme + */ + createScheme(scheme) { + return $clue.post(`grid/scheme/create`, scheme); + } +}; diff --git a/src/api/gridRecordApi.js b/src/api/gridRecordApi.js deleted file mode 100644 index 763882f..0000000 --- a/src/api/gridRecordApi.js +++ /dev/null @@ -1,55 +0,0 @@ -import { getGridRecordList } from '@/model/gridRecord'; - -export default { - /** - * 鑾峰彇鍏ㄩ儴缃戞牸鍖栬鍒掕褰� - */ - getGridRecords() { - return new Promise((resolve, reject) => { - resolve([ - { - value: '1', - label: '缃戞牸瑙勫垝鏂规涓�' - }, - { - value: '2', - label: '缃戞牸瑙勫垝鏂规浜�' - } - ]); - }); - }, - - /** - * 鏍规嵁鏂规璁板綍id锛岃幏鍙栧搴旂殑璁板綍璇︽儏 - * @param {String} recordId 鏂规璁板綍id - */ - getGridRecordDetail(recordId) { - return new Promise((resolve, reject) => { - const data = [ - { - gId: '1', - gName: '缃戞牸涓�', - gSide: [ - [121.01334, 31.232145], - [121.01434, 31.232145], - [121.01434, 31.233145], - [121.01334, 31.233145] - ] - } - ]; - for (let i = 0; i < 10; i++) { - const l = []; - data[i].gSide.forEach((p) => { - const lng = p[0] + 0.001; - l.push([lng, p[1]]); - }); - data.push({ - gId: i + 2 + '', - gName: '缃戞牸浜�', - gSide: l - }); - } - resolve(getGridRecordList(data)); - }); - } -}; diff --git a/src/api/index.js b/src/api/index.js index e69de29..0ff0550 100644 --- a/src/api/index.js +++ b/src/api/index.js @@ -0,0 +1,33 @@ +import axios from 'axios'; +import { setInterceptors } from "./config"; + +const url = 'http://47.100.191.150:9031/'; +// const url = 'http://192.168.1.9:8080/'; +const imgUrl = 'http://47.100.191.150:9031/images/'; + +//椋炵窘鐩戠 +const $clue = axios.create({ + baseURL: url, + timeout: 10000 + // headers: addHeaders() +}); + +// function getHeaders() { +// const token = 'e6dc8bb9e1ff0ce973fb92b4af2e4c3f'; + +// const date = new Date(); +// const timestamp = parseInt(date.getTime() / 1000) - 200; + +// const sign = md5(timestamp + token); + +// return { +// 'JA-TIMESTAMP': timestamp, +// 'JA-SIGN': sign, +// 'JA-TOKEN': token +// }; +// } + +//娣诲姞鎷︽埅鍣� +setInterceptors($clue) + +export { $clue, imgUrl }; diff --git a/src/assets/base.css b/src/assets/base.css index b15a559..5ae75b2 100644 --- a/src/assets/base.css +++ b/src/assets/base.css @@ -1,55 +1,3 @@ -/* color palette from <https://github.com/vuejs/theme> */ -:root { - --vt-c-white: #ffffff; - --vt-c-white-soft: #f8f8f8; - --vt-c-white-mute: #f2f2f2; - - --vt-c-black: #181818; - --vt-c-black-soft: #222222; - --vt-c-black-mute: #282828; - - --vt-c-indigo: #2c3e50; - - --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); - --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); - --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); - --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); - - --vt-c-text-light-1: var(--vt-c-indigo); - --vt-c-text-light-2: rgba(60, 60, 60, 0.66); - --vt-c-text-dark-1: var(--vt-c-white); - --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); -} - -/* semantic color variables for this project */ -:root { - --color-background: var(--vt-c-white); - --color-background-soft: var(--vt-c-white-soft); - --color-background-mute: var(--vt-c-white-mute); - - --color-border: var(--vt-c-divider-light-2); - --color-border-hover: var(--vt-c-divider-light-1); - - --color-heading: var(--vt-c-text-light-1); - --color-text: var(--vt-c-text-light-1); - - --section-gap: 160px; -} - -@media (prefers-color-scheme: dark) { - :root { - --color-background: var(--vt-c-black); - --color-background-soft: var(--vt-c-black-soft); - --color-background-mute: var(--vt-c-black-mute); - - --color-border: var(--vt-c-divider-dark-2); - --color-border-hover: var(--vt-c-divider-dark-1); - - --color-heading: var(--vt-c-text-dark-1); - --color-text: var(--vt-c-text-dark-2); - } -} - *, *::before, *::after { @@ -58,9 +6,23 @@ font-weight: normal; } +:root { + --fy-head-height: 50px; + --fy-body-height: calc(100% - var(--fy-head-height)); +} + +table { + border-collapse: collapse; + border-spacing: 0; +} + +td, th { + padding: 0; +} + body { - --screen-min-width: 1440px; - --screen-min-height: 900px; + --screen-min-width: 1200px; + --screen-min-height: 600px; min-height: var(--screen-min-height); min-width: var(--screen-min-width); /* overflow: scroll; */ diff --git a/src/assets/layout.css b/src/assets/layout.css new file mode 100644 index 0000000..9736a1a --- /dev/null +++ b/src/assets/layout.css @@ -0,0 +1,56 @@ +.fy-head { + height: var(--fy-head-height); +} + +.fy-body { + height: var(--fy-body-height); +} + +.fy-overlay-container { + pointer-events: none; + /* background-color: aqua; */ +} + +.fy-card { + position: relative; + /* height: 700px; */ + background: white; + border-radius: 12px; + display: flex; + flex-direction: column; + gap: 16px; + pointer-events: auto; + box-shadow: var(--el-box-shadow-dark); + /* padding: 0 8px; */ +} + +.fy-main { + /* background-color: aliceblue; */ + padding: 8px 8px 16px 8px; + font-size: var(--el-font-size-base); +} + +.fy-main-border { + /* background-color: aliceblue; */ + padding: 0 8px; + font-size: var(--el-font-size-base); + border: var(--el-border); + border-radius: 6px; +} + +.fy-column-reverse { + display: flex; + flex-direction: column-reverse; + height: 100%; +} + +.fy-flex-row { + display: flex; + align-items: center; + gap: 4px; + padding: 0 8px; +} + +.fy-flex-row>span{ + color: var(--el-text-color-regular); +} \ No newline at end of file diff --git a/src/assets/main.css b/src/assets/main.css index 781f450..8cf314d 100644 --- a/src/assets/main.css +++ b/src/assets/main.css @@ -1,34 +1,10 @@ @import './base.css'; @import './border.css'; @import './text.css'; +@import './layout.css'; +@import './shortcut.css'; #app { margin: 0 auto; font-weight: normal; -} - -/* a, -.green { - text-decoration: none; - color: hsla(160, 100%, 37%, 1); - transition: 0.4s; -} */ - -@media (hover: hover) { - /* a:hover { - background-color: hsla(160, 100%, 37%, 0.2); - } */ -} - -@media (min-width: 1024px) { - /* body { - display: flex; - place-items: center; - } - - #app { - display: grid; - grid-template-columns: 1fr 1fr; - padding: 0 2rem; - } */ } \ No newline at end of file diff --git a/src/assets/shortcut.css b/src/assets/shortcut.css new file mode 100644 index 0000000..714f8ee --- /dev/null +++ b/src/assets/shortcut.css @@ -0,0 +1,16 @@ +.flex { + display: flex; +} + +.flex-col { + display: flex; + flex-direction: column; +} + +.gap-1 { + gap: 4px; +} + +.p-h-1 { + padding: 0 8px; +} \ No newline at end of file diff --git a/src/assets/text.css b/src/assets/text.css index 1dd790d..770facd 100644 --- a/src/assets/text.css +++ b/src/assets/text.css @@ -1,14 +1,16 @@ .fy-h1 { padding: 8px 8px 8px 8px; font-size: var(--el-font-size-large); + font-weight: 600; } .fy-h2 { - padding: 16px 0 8px 0; + padding: 8px 8px; font-size: var(--el-font-size-medium); display: flex; justify-content: space-between; align-items: center; + font-weight: 600; } .fy-p1 { diff --git a/src/components.d.ts b/src/components.d.ts index 0499a39..925dc48 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -8,26 +8,32 @@ declare module 'vue' { export interface GlobalComponents { BaseMap: typeof import('./components/map/BaseMap.vue')['default'] + CloseButton: typeof import('./components/button/CloseButton.vue')['default'] + CoreHeader: typeof import('./components/core/CoreHeader.vue')['default'] + DescriptionsList: typeof import('./components/list/DescriptionsList.vue')['default'] + DescriptionsListItem: typeof import('./components/list/DescriptionsListItem.vue')['default'] ElButton: typeof import('element-plus/es')['ElButton'] ElButtonGroup: typeof import('element-plus/es')['ElButtonGroup'] ElCol: typeof import('element-plus/es')['ElCol'] ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider'] ElDatePicker: typeof import('element-plus/es')['ElDatePicker'] - ElDescriptions: typeof import('element-plus/es')['ElDescriptions'] - ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem'] ElDialog: typeof import('element-plus/es')['ElDialog'] ElDivider: typeof import('element-plus/es')['ElDivider'] ElEmpty: typeof import('element-plus/es')['ElEmpty'] ElForm: typeof import('element-plus/es')['ElForm'] ElFormItem: typeof import('element-plus/es')['ElFormItem'] ElIcon: typeof import('element-plus/es')['ElIcon'] + ElImageViewer: typeof import('element-plus/es')['ElImageViewer'] ElInput: typeof import('element-plus/es')['ElInput'] ElOption: typeof import('element-plus/es')['ElOption'] ElRadio: typeof import('element-plus/es')['ElRadio'] + ElRadioButton: typeof import('element-plus/es')['ElRadioButton'] ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup'] ElRow: typeof import('element-plus/es')['ElRow'] ElScrollbar: typeof import('element-plus/es')['ElScrollbar'] ElSelect: typeof import('element-plus/es')['ElSelect'] + ElTag: typeof import('element-plus/es')['ElTag'] + ElText: typeof import('element-plus/es')['ElText'] ElUpload: typeof import('element-plus/es')['ElUpload'] MapSearch: typeof import('./components/map/MapSearch.vue')['default'] OptionTime: typeof import('./components/search-option/OptionTime.vue')['default'] diff --git a/src/components/button/CloseButton.vue b/src/components/button/CloseButton.vue new file mode 100644 index 0000000..aaf5736 --- /dev/null +++ b/src/components/button/CloseButton.vue @@ -0,0 +1,36 @@ +<template> + <div class="wrapper"> + <el-button + class="close-btn" + type="danger" + icon="Close" + circle + @click="close" + /> + <slot></slot> + </div> +</template> + +<script> +export default { + emits: ['close'], + methods: { + close() { + this.$emit('close'); + } + } +}; +</script> +<style scoped> +.wrapper { + position: relative; + padding-right: 10px; + pointer-events: auto; +} +.close-btn { + position: absolute; + right: 2px; + top: -10px; + z-index: 1; +} +</style> diff --git a/src/components/core/CoreHeader.vue b/src/components/core/CoreHeader.vue new file mode 100644 index 0000000..7465b24 --- /dev/null +++ b/src/components/core/CoreHeader.vue @@ -0,0 +1,44 @@ +<template> + <el-row class="fy-head"> + <div> + <el-radio-group + class="container" + v-model="radio1" + size="large" + @change="onChange" + > + <el-radio-button + v-for="item in radioOptions" + :key="item.label" + :label="item.label" + >{{ item.name }}</el-radio-button + > + </el-radio-group> + </div> + </el-row> +</template> + +<script> +export default { + emits: ['onChange'], + data() { + return { + radioOptions: [ + { name: '绾跨储绠$悊', label: 0 }, + { name: '缃戞牸绠$悊', label: 1 } + ], + radio1: 0 + }; + }, + methods: { + onChange(e) { + this.$emit('onChange', e); + } + } +}; +</script> +<style scoped> +.container { + pointer-events: auto; +} +</style> diff --git a/src/components/list/DescriptionsList.vue b/src/components/list/DescriptionsList.vue new file mode 100644 index 0000000..4afb85a --- /dev/null +++ b/src/components/list/DescriptionsList.vue @@ -0,0 +1,31 @@ +<template> + <div class="title-wrapper"> + <div v-if="title" class="fy-h2">{{ title }}</div> + <slot name="extra"></slot> + </div> + <table> + <tbody> + <slot></slot> + </tbody> + </table> +</template> + +<script> +export default { + props: { + title: String + } +}; +</script> + +<style scoped> +.title-wrapper { + display: flex; + justify-content: space-between; + align-items: center; +} + +table { + width: 100%; +} +</style> diff --git a/src/components/list/DescriptionsListItem.vue b/src/components/list/DescriptionsListItem.vue new file mode 100644 index 0000000..65e34c8 --- /dev/null +++ b/src/components/list/DescriptionsListItem.vue @@ -0,0 +1,36 @@ +<template> + <tr> + <td v-if="label" class="td-1">{{ label }}</td> + <td v-else class="td-1"><slot name="label"></slot></td> + <td v-if="content" class="td-2">{{ content }}</td> + <td v-else class="td-2"><slot name="content"></slot></td> + </tr> +</template> + +<script> +export default { + props: { + label: String, + content: String + } +}; +</script> + +<style scoped> +tr { + font-size: var(--el-font-size-small); +} +td { + border: var(--el-border); + padding: 2px 6px; +} +.td-1 { + width: 68px; + background-color: var(--el-fill-color-light); + color: var(--el-text-color-regular); +} + +.td-2 { + color: var(--el-text-color-primary); +} +</style> diff --git a/src/components/map/baseMapUtil.js b/src/components/map/baseMapUtil.js index 735b58e..02b6601 100644 --- a/src/components/map/baseMapUtil.js +++ b/src/components/map/baseMapUtil.js @@ -80,21 +80,31 @@ }); }, + addMarker(lnglat) { + const marker = new AMap.Marker({ + position: lnglat + }); + map.add(marker); + this.setCenter(lnglat); + return marker; + }, + + setCenter(lnglat) { + map.setCenter(lnglat); + }, + /** * 缂╂斁鍦板浘鍒板悎閫傜殑瑙嗛噹绾у埆 */ - setFitView(overlays, type = 0) { + setFitView(...overlays) { const _overlays = toRaw(overlays); - switch (type) { - case 0: - map.setFitView([_overlays]); - break; - case 1: - map.setFitView(_overlays); - break; - default: - map.setFitView([_overlays]); - break; + map.setFitView(_overlays, true, [60, 60, 500, 60], 14.5); + }, + + addView(overlays) { + if (overlays) { + const _overlays = toRaw(overlays); + map.add(_overlays); } }, @@ -102,8 +112,10 @@ * 绉婚櫎瑕嗙洊鐗� */ removeView(overlays) { - const _overlays = toRaw(overlays); - map.remove(_overlays); + if (overlays) { + const _overlays = toRaw(overlays); + map.remove(_overlays); + } }, /** @@ -133,8 +145,10 @@ (((a * (1 - ee)) / (magic * sqrtmagic)) * PI); dlng = (dlng * 180.0) / ((a / sqrtmagic) * Math.cos(radlat) * PI); - let mglat = Math.round((lat * 2 - lat - dlat) * 1000000) / 1000000; - let mglng = Math.round((lng * 2 - lng - dlng) * 1000000) / 1000000; + let mglat = + Math.round((lat * 2 - lat - dlat) * 1000000) / 1000000; + let mglng = + Math.round((lng * 2 - lng - dlng) * 1000000) / 1000000; return [mglng, mglat]; } }, @@ -164,5 +178,16 @@ let mglng = Math.round((lng + dlng) * 1000000) / 1000000; return [mglng, mglat]; } + }, + gpsConvert(gps) { + return new Promise((reject) => { + // 鍙傛暟璇存槑锛氶渶瑕佽浆鎹㈢殑鍧愭爣锛岄渶瑕佽浆鎹㈢殑鍧愭爣绫诲瀷锛岃浆鎹㈡垚鍔熷悗鐨勫洖璋冨嚱鏁� + AMap.convertFrom(gps, 'baidu', function (status, result) { + if (result.info === 'ok') { + var lnglats = result.locations; // 杞崲鍚庣殑楂樺痉鍧愭爣 Array.<LngLat> + reject(lnglats[0]); + } + }); + }); } }; diff --git a/src/components/map/mapGrid.js b/src/components/map/mapGrid.js index 9f630ce..d16d8ba 100644 --- a/src/components/map/mapGrid.js +++ b/src/components/map/mapGrid.js @@ -37,10 +37,10 @@ }; mouseTool.on('draw', lastDrawEvent); mouseTool.polygon({ - strokeColor: '#FF33FF', + strokeColor: 'green', strokeOpacity: 1, - strokeWeight: 6, - fillColor: '#1791fc', + strokeWeight: 2, + fillColor: '#fff', fillOpacity: 0.4, // 绾挎牱寮忚繕鏀寔 'dashed' strokeStyle: 'solid' diff --git a/src/components/search-option/OptionTime.vue b/src/components/search-option/OptionTime.vue index 572283e..7c92ea3 100644 --- a/src/components/search-option/OptionTime.vue +++ b/src/components/search-option/OptionTime.vue @@ -9,7 +9,7 @@ <script> // 缃戞牸鍖栨柟妗堣褰曢�夐」 -import gridRecordApi from '@/api/gridRecordApi'; +import gridSchemeApi from '@/api/grid/gridSchemeApi'; export default { props: { @@ -37,7 +37,7 @@ }, methods: { getOptions() { - gridRecordApi.getGridRecords().then((res) => { + gridSchemeApi.getGridRecords().then((res) => { this.options = res; this.selectedOptions = res[0]; }); diff --git a/src/composables/formConfirm.js b/src/composables/formConfirm.js index 43b3d35..f036d0b 100644 --- a/src/composables/formConfirm.js +++ b/src/composables/formConfirm.js @@ -75,9 +75,10 @@ // 娓呯┖琛ㄥ崟 const clear = function () { + formRef.value.clearValidate(); edit.value = false; isReset = true; - formObj.value = {} + formObj.value = {}; }; // 鎻愪氦鎴愬姛鍚� @@ -94,9 +95,9 @@ confirmMsg: submit.msg, confirmTitle: submit.title, onConfirm: async () => { - await submit.do(); - submited(); - return; + return submit.do().then(() => { + submited(); + }); } }); } @@ -116,6 +117,7 @@ } }); } else { + formRef.value.clearValidate(); cancel.do(); } }; @@ -142,5 +144,14 @@ } }; - return { formObj, formRef, edit, active, onSubmit, onCancel, onReset, clear }; + return { + formObj, + formRef, + edit, + active, + onSubmit, + onCancel, + onReset, + clear + }; } diff --git a/src/composables/messageBox.js b/src/composables/messageBox.js index d896244..3f43447 100644 --- a/src/composables/messageBox.js +++ b/src/composables/messageBox.js @@ -1,31 +1,45 @@ -import { ElMessageBox, ElNotification, ElMessage } from 'element-plus'; +import { + ElMessageBox, + ElNotification, + ElMessage +} from 'element-plus'; function useMessageBoxTip({ confirmMsg, confirmTitle = '鎻愪氦', doneMsg = confirmTitle, - onConfirm, + onConfirm }) { ElMessageBox.confirm(confirmMsg, `${confirmTitle}纭`, { confirmButtonText: '纭', cancelButtonText: '鍙栨秷', - type: 'warning', + type: 'warning' }) .then(async () => { - let msg = `宸�${doneMsg}` + let msg = `宸�${doneMsg}`; if (typeof onConfirm === 'function') { - const str = await onConfirm(); - if (str && str != '') { - msg = `宸�${doneMsg}, ${str}` - } + onConfirm() + .then((res) => { + if (res && res != '') { + msg = `宸�${doneMsg}, ${res}`; + } + ElNotification({ + title: `${confirmTitle}鎴愬姛`, + message: msg, + type: 'success' + }); + }) + .catch((err) => { + let errStr = `${confirmTitle}鍙栨秷`; + if (err != 'cancel') { + errStr = `${confirmTitle}澶辫触, ${err}`; + } + ElMessage({ + message: errStr, + type: 'warning' + }); + }); } - ElNotification({ - title: `${confirmTitle}鎴愬姛`, - message: msg, - type: 'success', - // offset: 170, - position: 'bottom-left', - }); }) .catch((err) => { let errStr = `${confirmTitle}鍙栨秷`; @@ -34,7 +48,7 @@ } ElMessage({ message: errStr, - type: 'warning', + type: 'warning' }); }); } @@ -43,7 +57,7 @@ ElMessageBox.confirm(confirmMsg, confirmTitle, { confirmButtonText: '纭', cancelButtonText: '鍙栨秷', - type: 'warning', + type: 'warning' }) .then(async () => { if (typeof onConfirm === 'function') { diff --git a/src/main.js b/src/main.js index 4ff35b4..24d614c 100644 --- a/src/main.js +++ b/src/main.js @@ -4,6 +4,7 @@ import { createPinia } from 'pinia'; import App from './App.vue'; import { createMap } from './components/map/baseMap'; +import { tf, nf } from './utils/textFormat'; import * as ElementPlusIconsVue from '@element-plus/icons-vue'; import 'element-plus/theme-chalk/src/overlay.scss'; @@ -20,6 +21,8 @@ // 楂樺痉鍦板浘鍒濆鍖� createMap('container'); - +// 鎸傝浇鏃堕棿鏍煎紡鍖栧嚱鏁拌嚦鍏ㄥ眬 +app.config.globalProperties.$tf = tf; +app.config.globalProperties.$nf = nf; app.use(createPinia()).mount('#app'); diff --git a/src/model/clueQuestion.js b/src/model/clueQuestion.js index dc7d77f..87954a4 100644 --- a/src/model/clueQuestion.js +++ b/src/model/clueQuestion.js @@ -1,4 +1,4 @@ -import { imgUrl } from '@/api/clue/index'; +import { imgUrl } from '@/api/index'; function getClueQuestion(data) { data.cqFilePath = data.cqFilePath.split(';').map((val) => { diff --git a/src/model/gridRecord.js b/src/model/gridRecord.js index d991ac8..de996b7 100644 --- a/src/model/gridRecord.js +++ b/src/model/gridRecord.js @@ -6,9 +6,29 @@ * @returns */ function getGridRecord(data) { - const path = util.listToLngLat(data.gSide); - data.gSide = path; - return data; + const _sides = data.giSide.split(';').map((value) => { + return value.split(','); + }); + const _data = { + id: data.giUid, + schemeId: data.gsId, + name: data.giName, + sides: util.listToLngLat(_sides), + delete: data.giDelete, + createTime: data.giCreateTime + }; + return _data; +} + +function parseToGridInfo(data) { + return { + giUid: data.id, + gsId: data.schemeId, + giName: data.name, + giSide: data.overlays.getPath().join(';'), + giDelete: data.delete, + giCreateTime: data.createTime + }; } function getGridRecordList(dataList) { @@ -17,4 +37,4 @@ }); } -export { getGridRecord, getGridRecordList }; +export { getGridRecord, getGridRecordList, parseToGridInfo }; diff --git a/src/stores/grid.js b/src/stores/grid.js index 56ea718..23dac47 100644 --- a/src/stores/grid.js +++ b/src/stores/grid.js @@ -2,21 +2,27 @@ import { defineStore } from 'pinia'; import mapGrid from '@/components/map/mapGrid'; import baseMapUtil from '@/components/map/baseMapUtil'; +import gridInfoApi from '@/api/grid/gridInfoApi'; +import { parseToGridInfo } from '@/model/gridRecord'; export const useGridStore = defineStore('grid', () => { // 褰撳墠鍔犺浇鐨勭綉鏍兼暟鎹泦鍚� const gridList = ref([]); + // 褰撳墠鏄惁鏈夐�変腑鏂规 + const hasScheme = ref(false); // 褰撳墠閫変腑鎿嶄綔鐨勭綉鏍间俊鎭� - const selectedGrid = ref({}); + const selectedGrid = ref(); // 褰撳墠閫変腑鎿嶄綔鐨勭綉鏍兼槸鍚﹀浜庡彲缂栬緫鐘舵�� const isEdit = ref(false); + // 璁板綍褰撳墠缃戞牸璺緞淇℃伅 + var selectedPath = undefined; /** * 妫�鏌ュ綋鍓嶆槸鍚︽湁閫変腑鐨勭綉鏍� * @returns {Boolean} */ function _checkGridExist() { - return selectedGrid.value.gId != undefined; + return selectedGrid.value && selectedGrid.value.id != undefined; } /**鏁版嵁澧炲垹**************************************************************/ @@ -27,7 +33,16 @@ function setGrid(index) { if (index >= 0 && index < gridList.value.length) { selectedGrid.value = gridList.value[index]; + selectedPath = selectedGrid.value.overlays.getPath().join(';'); } + } + + /** + * 鍙栨秷閫変腑 + */ + function clearSelect() { + selectedGrid.value = undefined; + selectedPath = undefined; } /** @@ -36,6 +51,7 @@ */ function setGridList(list) { gridList.value = list; + hasScheme.value = true; } /** @@ -88,7 +104,14 @@ */ function saveSelectedGrid() { if (!_checkGridExist()) return; - selectedGrid.value.gSide = selectedGrid.value.overlays.getPath(); + const newPath = selectedGrid.value.overlays.getPath().join(';'); + if (selectedPath != newPath) { + const _data = parseToGridInfo(selectedGrid.value); + return gridInfoApi.updateGrid(_data).then(() => { + selectedGrid.value.sides = + selectedGrid.value.overlays.getPath(); + }); + } } /** @@ -98,7 +121,7 @@ if (!_checkGridExist()) return; baseMapUtil.removeView(selectedGrid.value.overlays); selectedGrid.value.overlays = mapGrid.drawPolygon( - selectedGrid.value.gSide + selectedGrid.value.sides ); } @@ -112,7 +135,7 @@ showGrid(i); grids.push(l.overlays); }); - baseMapUtil.setFitView(grids, 1); + baseMapUtil.setFitView(...grids); } /** @@ -123,15 +146,17 @@ if (item.overlays) { baseMapUtil.setFitView(item.overlays); } else { - item.overlays = mapGrid.drawPolygon(item.gSide); + item.overlays = mapGrid.drawPolygon(item.sides); } } return { + hasScheme, gridList, selectedGrid, isEdit, setGrid, + clearSelect, setGridList, addGrid, deleteGrid, diff --git a/src/utils/textFormat.js b/src/utils/textFormat.js new file mode 100644 index 0000000..0504a28 --- /dev/null +++ b/src/utils/textFormat.js @@ -0,0 +1,19 @@ +/** + * 鏂囨湰鏍峰紡鏍煎紡鍖� + */ + +import moment from 'moment'; + +function tf(timeStr) { + return moment(timeStr).format('YYYY-MM-DD HH:mm:ss'); +} + +function nf(num, digit = 2) { + let numStr = num + ''; + while (numStr.length < digit) { + numStr = '0' + numStr; + } + return numStr; +} + +export { tf, nf }; diff --git a/src/views/HomePage.vue b/src/views/HomePage.vue index 8445b25..4ede8f0 100644 --- a/src/views/HomePage.vue +++ b/src/views/HomePage.vue @@ -1,16 +1,22 @@ <template> <BaseMap></BaseMap> <div class="overlay-container"> + <CoreHeader @on-change="(e) => (menuIndex = e)"></CoreHeader> <!-- <router-view> --> - <!-- <GridLayout></GridLayout> --> - <ClueLayout></ClueLayout> + <ClueLayout v-show="menuIndex == 0"></ClueLayout> + <GridLayout v-show="menuIndex == 1"></GridLayout> <!-- </router-view> --> </div> </template> <script setup> +import { ref } from 'vue'; + import GridLayout from '@/views/overlay-grid/GridLayout.vue'; import ClueLayout from '@/views/overlay-clue/ClueLayout.vue'; + +// 椁愬崟绱㈠紩 +const menuIndex = ref(0); </script> <style scoped> @@ -23,7 +29,7 @@ height: 100vh; top: 0; left: 0; - padding: 4px; + /* padding: 4px; */ pointer-events: none; } </style> diff --git a/src/views/overlay-clue/ClueLayout.vue b/src/views/overlay-clue/ClueLayout.vue index b47e870..be9e728 100644 --- a/src/views/overlay-clue/ClueLayout.vue +++ b/src/views/overlay-clue/ClueLayout.vue @@ -1,119 +1,32 @@ <template> - <el-row class="container" justify="space-between"> - <el-col :span="6" class="grid-content bg-content"> - <div class="fy-h1">绾跨储娓呭崟</div> - <div class="search-wrap"> - <span>鏃堕棿</span> - <el-date-picker - v-model="updateTime" - type="datetime" - placeholder="閫夋嫨鏃ユ湡鍜屾椂闂�" - /> - <el-button type="primary" @click="getClues">鏌ヨ</el-button> - <el-button type="primary" @click="fetchRemoteClue" - >鎷夊彇绾跨储</el-button - > - </div> - <ClueList - :dataList="clueList" - @itemSelected="selectClue" - ></ClueList> + <el-row class="fy-overlay-container" justify="space-between"> + <el-col :span="6"> + <ClueManage @itemSelected="selectClue"></ClueManage> </el-col> - <el-col :span="6" class="grid-content bg-content-1"> - <div class="fy-h1">绾跨储鍙嶉</div> - <el-scrollbar height="80vh" class="bg-fill"> - <ClueReport :clueData="selectedClue"></ClueReport> - </el-scrollbar> + <el-col :span="6"> + <ClueReport + v-model:show="show" + :clueData="selectedClue" + ></ClueReport> </el-col> </el-row> </template> <script setup> -import ClueList from './components/ClueList.vue'; -import ClueReport from './components/ClueReport.vue'; +import ClueManage from './list/ClueManage.vue'; +import ClueReport from './report/ClueReport.vue'; +import { ref } from 'vue'; -import clueApi from '@/api/clue/clueApi'; -import { onMapMounted } from '@/components/map/baseMap'; -import moment from 'moment'; -import { ref, watch } from 'vue'; - -// 涓嬪彂鏃堕棿锛堟瘡娆℃煡璇㈠ぇ浜庢鏃堕棿鐨勬暟鎹級 -const updateTime = ref(new Date()); -// 绾跨储娓呭崟 -const clueList = ref([]); const selectedClue = ref(); - -/** - * 鏌ヨ宸蹭笅鍙戠殑绾跨储娓呭崟 - */ -const getClues = function () { - const now = moment(updateTime.value); - const sTime = now.format('YYYY-MM-DD HH:mm:ss'); - const eTime = now.add(1, 'month').format('YYYY-MM-DD HH:mm:ss'); - onMapMounted(() => { - clueApi.getClue({ sTime, eTime }).then((res) => { - clueList.value = res; - }); - }); -}; - -function fetchRemoteClue() { - const time = moment(updateTime.value).format('YYYY-MM-DD HH:mm:ss'); - onMapMounted(() => { - clueApi.fetchRemoteClue(time).then((res) => { - clueList.value = res; - }); - }); -} +const show = ref(false); /** * 閫夋嫨绾跨储浜嬩欢 */ const selectClue = function (clue) { + show.value = true; selectedClue.value = clue; }; </script> -<style scoped> -.title { - font-size: var(--el-font-size-large); -} - -.container { - pointer-events: none; -} - -.grid-content { - /* min-width: 180px; */ - border-radius: var(--el-border-radius-round); - display: flex; - flex-direction: column; - gap: 16px; - /* padding: 8px 8px; */ - pointer-events: auto; - box-shadow: var(--el-box-shadow-dark); -} - -.bg-content { - height: 90vh; - background: white; - min-width: calc(var(--screen-min-width) / 6); -} - -.bg-content-1 { - height: 90vh; - background: white; -} - -.search-wrap { - padding: 0 8px; - display: flex; - align-items: center; - gap: 4px; -} - -.bg-fill { - /* background: var(--el-fill-color-extra-light); */ - padding: 0 8px; -} -</style> +<style scoped></style> diff --git a/src/views/overlay-clue/components/ClueList.vue b/src/views/overlay-clue/components/ClueList.vue deleted file mode 100644 index 2b49cd8..0000000 --- a/src/views/overlay-clue/components/ClueList.vue +++ /dev/null @@ -1,92 +0,0 @@ -<template> - <ul class="list-container"> - <el-scrollbar> - <template v-for="(item, index) in dataList" :key="index"> - <li - :class=" - 'list-item ' + - (item.selected ? 'list-item__selected' : '') - " - @click="selectItem(item)" - v-if="!item.delete" - > - <div style="display: flex; gap: 8px"> - <div>{{ item.cid }}</div> - <div>{{ item.cclueName }}</div> - </div> - </li> - </template> - </el-scrollbar> - </ul> -</template> - -<script> -export default { - props: { - dataList: Array - }, - emits: ['itemSelected'], - data() { - return {}; - }, - watch: {}, - methods: { - // 鍒楄〃閫夋嫨 - selectItem(item) { - this.clearSelect(); - item.selected = true; - this.$emit('itemSelected', item); - }, - clearSelect() { - this.dataList.forEach((e) => { - e.selected = false; - }); - } - } -}; -</script> -<style scoped> -.list-container { - /* background-color: antiquewhite; */ - padding: initial; - height: 50vh; - overflow: auto; - overflow-x: hidden; - border: var(--el-border); - font-size: var(--el-font-size-small); -} - -.list-item { - display: flex; - justify-content: space-between; - align-items: center; - padding: 4px; - list-style-type: none; - /* background-color: aqua; */ - /* border: var(--el-border); */ - border-radius: var(--el-border-radius-base); - box-shadow: var(--el-box-shadow-lighter); - margin-bottom: 2px; - cursor: pointer; - line-height: 36px; -} - -.list-item:hover { - background-color: var(--el-color-primary-light-9); -} - -.list-item__selected { - background-color: var(--el-color-primary-light-9); -} - -.v-enter-from, -.v-leave-to { - opacity: 0; - transform: translateX(8px); -} - -.v-enter-active, -.v-leave-active { - transition: all 0.3s ease-out; -} -</style> diff --git a/src/views/overlay-clue/components/ClueReport.vue b/src/views/overlay-clue/components/ClueReport.vue deleted file mode 100644 index 7ed612e..0000000 --- a/src/views/overlay-clue/components/ClueReport.vue +++ /dev/null @@ -1,104 +0,0 @@ -<template> - <!-- 娓呭崟璇︽儏 --> - <el-descriptions - class="" - title="绾跨储娓呭崟璇︽儏" - :column="1" - size="small" - border - > - <template #extra> - <el-button - type="primary" - text - size="small" - @click="openPDF" - >鏌ョ湅PDF</el-button - > - </template> - <el-descriptions-item> - <template #label> - <div class="cell-item">绾跨储缂栧彿</div> - </template> - {{ clueData.cid }} - </el-descriptions-item> - <el-descriptions-item width="65px" min-width="50px"> - <template #label> - <div class="cell-item">绾跨储鍚嶇О</div> - </template> - {{ clueData.cclueName }} - </el-descriptions-item> - <!-- <el-descriptions-item> - <template #label> - <div class="cell-item">鍒涘缓鏃堕棿</div> - </template> - {{ clueData.ccreateTime }} - </el-descriptions-item> --> - <el-descriptions-item> - <template #label> - <div class="cell-item">涓嬪彂鏃堕棿</div> - </template> - {{ clueData.creleaseTime }} - </el-descriptions-item> - <el-descriptions-item> - <template #label> - <div class="cell-item">鎶ヨ绔欑偣</div> - </template> - {{ clueData.csiteName }} - </el-descriptions-item> - <el-descriptions-item> - <template #label> - <div class="cell-item">绔欑偣绫诲瀷</div> - </template> - {{ clueData.csiteType }} - </el-descriptions-item> - <el-descriptions-item> - <template #label> - <div class="cell-item">绾跨储缁撹</div> - </template> - {{ clueData.cconclusion }} - </el-descriptions-item> - <!-- <el-descriptions-item> - <template #label> - <div class="cell-item">绔欑偣绫诲瀷閫夐」</div> - </template> - {{ clueData.cairCheckedOptions }} - </el-descriptions-item> --> - </el-descriptions> - <ClueReportConclusion :clueId="clueData.cid"></ClueReportConclusion> - <ClueReportQuestion :clueId="clueData.cid"></ClueReportQuestion> -</template> - -<script> -import ClueReportConclusion from './ClueReportConclusion.vue'; -import ClueReportQuestion from './ClueReportQuestion.vue'; -export default { - components: { ClueReportConclusion, ClueReportQuestion }, - props: { - clueData: { - type: Object, - default: () => { - return {}; - } - } - }, - name: 'HomePage', - data() { - return { - // 鍥剧墖涓婁紶鐨勫脊鍑烘 - isShowReportPhoto: false, - photoForm: { - clueId: 0, - questionDescription: '' - } - }; - }, - methods: { - openPDF() { - - } - } -}; -</script> - -<style></style> diff --git a/src/views/overlay-clue/list/ClueManage.vue b/src/views/overlay-clue/list/ClueManage.vue new file mode 100644 index 0000000..8519370 --- /dev/null +++ b/src/views/overlay-clue/list/ClueManage.vue @@ -0,0 +1,80 @@ +<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="primary" @click="fetchRemoteClue" plain + >鎷夊彇绾跨储</el-button + > + </div> + <el-scrollbar height="70vh" class="p-h-1"> + <ClueList + :dataList="clueList" + @itemSelected="selectClue" + ></ClueList> + </el-scrollbar> + </div> +</template> + +<script setup> +import ClueList from './components/ClueList.vue'; + +import clueApi from '@/api/clue/clueApi'; +import { onMapMounted } from '@/components/map/baseMap'; +import moment from 'moment'; +import { ref, onMounted } from 'vue'; + +const emits = defineEmits('itemSelected'); + +// 涓嬪彂鏃堕棿锛堟瘡娆℃煡璇㈠ぇ浜庢鏃堕棿鐨勬暟鎹級 +const updateTime = ref(); +// 绾跨储娓呭崟 +const clueList = ref([]); + +/** + * 鏌ヨ宸蹭笅鍙戠殑绾跨储娓呭崟 + */ +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(() => { + clueApi.getClue({ sTime, eTime }).then((res) => { + clueList.value = res; + }); + }); +}; + +function fetchRemoteClue() { + const time = moment(updateTime.value).format('YYYY-MM-DD HH:mm:ss'); + onMapMounted(() => { + clueApi.fetchRemoteClue(time).then((res) => { + clueList.value = res; + }); + }); +} + +/** + * 閫夋嫨绾跨储浜嬩欢 + */ +const selectClue = function (clue) { + emits('itemSelected', clue); +}; + +onMounted(() => { + getClues(); +}); +</script> +<style scoped> + +</style> \ No newline at end of file diff --git a/src/views/overlay-clue/list/components/ClueList.vue b/src/views/overlay-clue/list/components/ClueList.vue new file mode 100644 index 0000000..9aa4250 --- /dev/null +++ b/src/views/overlay-clue/list/components/ClueList.vue @@ -0,0 +1,138 @@ +<template> + <ul class="list-container"> + <template v-for="(item, index) in dataList" :key="index"> + <li + :class=" + 'list-item ' + (item.selected ? 'list-item__selected' : '') + " + @click="selectItem(item)" + v-if="!item.delete" + > + <div class="clue-item"> + <div class="flex gap-1"> + <div class="clue-num">{{ $nf(item.cid) }}</div> + <el-text class="fy-h1" truncated>{{ item.cclueName }}</el-text> + </div> + <div class="flex gap-1"> + <div class=""> + <el-text type="info" size="small">缁撹锛�</el-text> + <el-text size="small">{{ item.conclusionCount + '/1' }}</el-text> + </div> + <div class=""> + <el-text type="info" size="small">闂锛�</el-text> + <el-text size="small">{{ item.questionCount }}</el-text> + </div> + <el-text type="info" size="small">{{item.cuploaded ? '宸叉帹閫�' : '鏈帹閫�'}}</el-text> + </div> + <el-row justify="space-between"> + <span class="flex gap-1"> + <el-tag v-if="item.csiteType" size="default" type="info">{{ + item.csiteType + }}</el-tag> + <el-tag v-if="item.cfactor" size="default" effect="" type="danger">{{ + item.cfactor + }}</el-tag> + </span> + <el-text size="small">涓嬪彂鏃堕棿锛歿{ + $tf(item.creleaseTime) + }}</el-text> + </el-row> + </div> + </li> + </template> + </ul> +</template> + +<script> +import baseMapUtil from '@/components/map/baseMapUtil'; + +var _marker; +export default { + props: { + dataList: Array + }, + emits: ['itemSelected'], + data() { + return {}; + }, + watch: {}, + methods: { + // 鍒楄〃閫夋嫨 + selectItem(item) { + this.clearSelect(); + item.selected = true; + // const lnglat = baseMapUtil.wgs84togcj02( + // item.clongitude, + // item.clatitude + // ); + baseMapUtil + .gpsConvert([item.clongitude, item.clatitude]) + .then((lnglat) => { + baseMapUtil.removeView(_marker); + _marker = baseMapUtil.addMarker(lnglat); + }); + this.$emit('itemSelected', item); + }, + clearSelect() { + this.dataList.forEach((e) => { + e.selected = false; + }); + } + } +}; +</script> +<style scoped> +.list-container { + padding: initial; + /* border: var(--el-border); */ + font-size: var(--el-font-size-base); +} + +.list-item { + padding: 4px; + list-style-type: none; + border: var(--el-border); + border-radius: var(--el-border-radius-base); + box-shadow: var(--el-box-shadow-lighter); + margin-bottom: 6px; + cursor: pointer; +} + +.list-item:hover { + background-color: var(--el-color-primary-light-9); +} + +.list-item__selected { + background-color: var(--el-color-primary-light-9); +} + +.v-enter-from, +.v-leave-to { + opacity: 0; + transform: translateX(8px); +} + +.v-enter-active, +.v-leave-active { + transition: all 0.3s ease-out; +} + +.clue-item { + display: flex; + flex-direction: column; + gap: 10px; +} + +.clue-num { + font-size: 16px; + font-weight: 700; + font-style: italic; + color: var(--el-color-primary); +} + +.clue-tag { + display: flex; + flex-direction: column; + justify-content: flex-start; +} +</style> diff --git a/src/views/overlay-clue/report/ClueReport.vue b/src/views/overlay-clue/report/ClueReport.vue new file mode 100644 index 0000000..97f98d4 --- /dev/null +++ b/src/views/overlay-clue/report/ClueReport.vue @@ -0,0 +1,107 @@ +<template> + <!-- 娓呭崟璇︽儏 --> + <CloseButton v-show="show" @close="closeEdit"> + <el-button + class="push-btn" + :type="clueData.cuploaded ? 'success' : 'danger'" + @click="pushCheck" + :disabled="clueData.cuploaded" + ><div class="flex-col"> + <template v-if="clueData.cuploaded"> + <el-icon><Check /></el-icon> + <div>宸�</div> + <div>鎺�</div> + <div>閫�</div> + </template> + <template v-else> + <el-icon><Upload /></el-icon> + <div>鎺�</div> + <div>閫�</div> + <div>鍙�</div> + <div>棣�</div> + </template> + </div></el-button + > + <div class="fy-card"> + <div class="fy-h1">绾跨储鍙嶉</div> + <el-scrollbar height="80vh" class="p-h-1"> + <ClueReportClue :clue="clueData"></ClueReportClue> + <ClueReportConclusion + :clueId="clueData.cid" + ></ClueReportConclusion> + <ClueReportQuestion + :clueId="clueData.cid" + ></ClueReportQuestion> + </el-scrollbar> + </div> + </CloseButton> +</template> + +<script> +import ClueReportClue from './components/ClueReportClue.vue'; +import ClueReportConclusion from './components/ClueReportConclusion.vue'; +import ClueReportQuestion from './components/ClueReportQuestion.vue'; +import { useMessageBoxTip } from '@/composables/messageBox'; +import clueApi from "@/api/clue/clueApi"; + +export default { + components: { + ClueReportClue, + ClueReportConclusion, + ClueReportQuestion + }, + props: { + clueData: { + type: Object, + default: () => { + return {}; + } + }, + show: Boolean + }, + emits: ['update:show'], + data() { + return {}; + }, + methods: { + closeEdit() { + this.$emit('update:show', false); + }, + pushCheck() { + useMessageBoxTip({ + confirmMsg: '绾跨储鎺ㄩ�佸悗鏃犳硶鍐嶄慨鏀圭粨璁轰笌闂锛岀‘璁ゆ帹閫侊紵', + confirmTitle: '绾跨储鎺ㄩ��', + onConfirm: () => { + return this.pushClue(); + } + }); + }, + pushClue() { + return clueApi.pushClue(this.clueData.cid) + } + } +}; +</script> + +<style scoped> +.push-btn { + position: absolute; + z-index: 1; + top: 2rem; + left: -2.5rem; + width: 2.5rem; + height: initial; + margin: initial; + display: flex; + flex-direction: column; + align-items: center; + /* background-color: white; */ + /* border-color: white; */ + /* border-top: 1px solid; + border-left: 1px solid; + border-bottom: 1px solid; */ + border-top-right-radius: 0px; + border-bottom-right-radius: 0px; + /* box-shadow: var(--el-box-shadow-light); */ +} +</style> diff --git a/src/views/overlay-clue/report/components/ClueReportClue.vue b/src/views/overlay-clue/report/components/ClueReportClue.vue new file mode 100644 index 0000000..6010893 --- /dev/null +++ b/src/views/overlay-clue/report/components/ClueReportClue.vue @@ -0,0 +1,51 @@ +<template> + <!-- 娓呭崟璇︽儏 --> + <DescriptionsList title="绾跨储娓呭崟璇︽儏"> + <template #extra> + <el-button type="primary" text size="small" @click="openPDF" + >鏌ョ湅PDF</el-button + > + </template> + <DescriptionsListItem label="绾跨储缂栧彿" :content="clue.cid" /> + <DescriptionsListItem + label="绾跨储鍚嶇О" + :content="clue.cclueName" + /> + <DescriptionsListItem label="鍒涘缓鏃堕棿" :content="$tf(clue.ccreateTime)" /> + <DescriptionsListItem label="涓嬪彂鏃堕棿" :content="$tf(clue.creleaseTime)" /> + <DescriptionsListItem + label="鎶ヨ绔欑偣" + :content="clue.csiteName" + /> + <DescriptionsListItem + label="绔欑偣绫诲瀷" + :content="clue.csiteType" + /> + <DescriptionsListItem + label="绾跨储缁撹" + :content="clue.cconclusion" + /> + <!-- <DescriptionsListItem + label="绔欑偣绫诲瀷閫夐」" + :content="clue.cairCheckedOptions" + /> --> + </DescriptionsList> +</template> + +<script> +import clueApi from '@/api/clue/clueApi'; + +export default { + props: { + clue: Object + }, + methods: { + openPDF() { + window.open( + clueApi.fetchRemoteClueFileUrl(this.clue.cid), + '_blank' + ); + } + }, +}; +</script> diff --git a/src/views/overlay-clue/components/ClueReportConclusion.vue b/src/views/overlay-clue/report/components/ClueReportConclusion.vue similarity index 79% rename from src/views/overlay-clue/components/ClueReportConclusion.vue rename to src/views/overlay-clue/report/components/ClueReportConclusion.vue index a42a427..31634b2 100644 --- a/src/views/overlay-clue/components/ClueReportConclusion.vue +++ b/src/views/overlay-clue/report/components/ClueReportConclusion.vue @@ -1,31 +1,31 @@ <template> - <div class="fy-h2"> - 绾跨储缁撹 - <el-button - v-if="conclusion" - type="warning" - size="small" - plain - icon="Upload" - @click="pushConclusion" - :disabled="pushing ? true : conclusion.ccUploaded" - >{{ pushing ? '鎺ㄩ�佷腑' : pushText }}</el-button - > - </div> - <el-descriptions v-if="conclusion" :column="1" size="small" border> - <el-descriptions-item width="1px" min-width="30px"> - <template #label> - <div class="descriptions-item">闂绫诲瀷</div> - </template> - {{ conclusion.ccQuestionType }} - </el-descriptions-item> - <el-descriptions-item label="绾跨储缁撹"> - {{ conclusion.ccConclusion }} - </el-descriptions-item> - <el-descriptions-item label="璇︾粏鎻忚堪"> - {{ conclusion.ccDetails }} - </el-descriptions-item> - </el-descriptions> + <div class="fy-h2">绾跨储缁撹</div> + <DescriptionsList v-if="conclusion"> + <!-- <template #extra> + <el-button + v-if="conclusion" + type="warning" + size="small" + plain + icon="Upload" + @click="pushConclusion" + :disabled="pushing ? true : conclusion.ccUploaded" + >{{ pushing ? '鎺ㄩ�佷腑' : pushText }}</el-button + > + </template> --> + <DescriptionsListItem + label="闂绫诲瀷" + :content="conclusion.ccQuestionType" + /> + <DescriptionsListItem + label="绾跨储缁撹" + :content="conclusion.ccConclusion" + /> + <DescriptionsListItem + label="璇︾粏鎻忚堪" + :content="conclusion.ccDetails" + /> + </DescriptionsList> <div v-else class="fy-dashed-border"> <el-empty :image-size="50" description="绾跨储缁撹鏈笂浼�"> <el-button type="primary" @click="openDialog" @@ -187,7 +187,5 @@ }); </script> <style scoped> -.descriptions-item { - /* background: aqua; */ -} + </style> diff --git a/src/views/overlay-clue/components/ClueReportQuestion.vue b/src/views/overlay-clue/report/components/ClueReportQuestion.vue similarity index 61% rename from src/views/overlay-clue/components/ClueReportQuestion.vue rename to src/views/overlay-clue/report/components/ClueReportQuestion.vue index cc68613..bec32fd 100644 --- a/src/views/overlay-clue/components/ClueReportQuestion.vue +++ b/src/views/overlay-clue/report/components/ClueReportQuestion.vue @@ -1,17 +1,11 @@ <template> <div class="fy-h2">绾跨储闂</div> <template v-if="questionList.length > 0"> - <el-descriptions - v-for="(item, index) in questionList" - :title="'闂 ' + item.cqUid" - :key="index" - :column="2" - size="small" - border - > - <template #extra> - <el-button-group> - <el-button + <template v-for="(item, index) in questionList" :key="index"> + <DescriptionsList :title="item.cqUid"> + <template #extra> + <el-button-group> + <!-- <el-button type="warning" size="small" plain @@ -25,41 +19,30 @@ ? '鎺ㄩ�佷腑' : '鎺ㄩ�侀棶棰�' }}</el-button - > - <el-button - type="primary" - size="small" - @click="checkQuestion(item)" - >闂璇︽儏</el-button - > - </el-button-group> - </template> - <el-descriptions-item - width="1px" - min-width="70px" - label="闂缂栧彿" - > - {{ item.cqUid }} - </el-descriptions-item> - <el-descriptions-item label="鎵�鍦ㄨ闀�"> - {{ item.cqStreet }} - </el-descriptions-item> - <el-descriptions-item label="闂鎻忚堪"> - {{ item.cqDescription }} - </el-descriptions-item> - <!-- <el-descriptions-item label="璇︾粏鍦板潃"> - {{ item.cqAddress }} - </el-descriptions-item> - <el-descriptions-item label="缁忓害"> - {{ item.cqLongitude }} - </el-descriptions-item> - <el-descriptions-item label="绾害"> - {{ item.cqLatitude }} - </el-descriptions-item> - <el-descriptions-item label="鍒涘缓鏃堕棿"> - {{ item.cqCreateTime }} - </el-descriptions-item> --> - </el-descriptions> + > --> + <el-button + type="primary" + size="small" + @click="checkQuestion(item)" + >闂璇︽儏</el-button + > + </el-button-group> + </template> + <DescriptionsListItem + label="闂鍚嶇О" + :content="item.cqName" + /> + <DescriptionsListItem + label="鎵�鍦ㄨ闀�" + :content="item.cqStreet" + /> + <DescriptionsListItem + label="闂鎻忚堪" + :content="item.cqDescription" + /> + </DescriptionsList> + <!-- <el-divider /> --> + </template> <div class="btn-wrap"> <el-button type="primary" @click="openDialog" >娣诲姞闂</el-button @@ -128,7 +111,6 @@ item.pushing = true; }); } - </script> <style scoped> .btn-wrap { diff --git a/src/views/overlay-clue/components/QuestionDetail.vue b/src/views/overlay-clue/report/components/QuestionDetail.vue similarity index 76% rename from src/views/overlay-clue/components/QuestionDetail.vue rename to src/views/overlay-clue/report/components/QuestionDetail.vue index ac67c93..81c524a 100644 --- a/src/views/overlay-clue/components/QuestionDetail.vue +++ b/src/views/overlay-clue/report/components/QuestionDetail.vue @@ -7,7 +7,7 @@ destroy-on-close > <template #header> - <span> 鍙嶉闂</span> + <span> 娣诲姞闂</span> </template> <el-form label-width="90px" @@ -16,11 +16,17 @@ :model="formObj" ref="formRef" > + <el-form-item label="闂鍚嶇О" prop="cqName"> + <el-input + v-model="formObj.cqName" + placeholder="璇疯緭鍏ラ棶棰樺悕绉�" + ></el-input> + </el-form-item> <el-form-item label="闂鎻忚堪" prop="cqDescription"> <el-input v-model="formObj.cqDescription" type="textarea" - placeholder="璇疯緭鍏ヨ鎯�" + placeholder="璇疯緭鍏ラ棶棰樻弿杩�" ></el-input> </el-form-item> <el-form-item label="鎵�鍦ㄨ闀�" prop="cqStreet"> @@ -34,7 +40,10 @@ </el-select> </el-form-item> <el-form-item label="璇︾粏鍦板潃" prop="cqAddress"> - <el-input v-model="formObj.cqAddress"></el-input> + <el-input + v-model="formObj.cqAddress" + placeholder="璇疯緭鍏ュ湴鍧�鎴栬�呴�氳繃鈥滃潗鏍囨嬀鍙栤�濊嚜鍔ㄨ幏寰�" + ></el-input> </el-form-item> <el-form-item label="鍧愭爣" prop="coordinate"> <el-input @@ -57,6 +66,7 @@ accept="image/png, image/jpeg" :limit="3" multiple + :on-preview="handleFilePreview" :on-remove="handleFileRemove" :on-change="handleFileChange" > @@ -80,6 +90,13 @@ > </template> </el-dialog> + <el-image-viewer + v-if="previewShow" + :url-list="urlList" + :initial-index="initialIndex" + :infinite="false" + @close="closePreview" + ></el-image-viewer> <MapSearch v-model:show="mapDialogShow" @on-submit="selectAddress" @@ -99,13 +116,30 @@ question: Object }); -const emit = defineEmits(['update:show', 'onSubmit'], ['onClose']); +const emit = defineEmits(['update:show', 'onSubmit', 'onClose']); // 涓婃姤寮瑰嚭妗� const dialogShow = ref(false); const mapDialogShow = ref(false); const uploadRef = ref(); const fileList = ref([]); + +const previewShow = ref(false); +const initialIndex = ref(0); +const urlList = computed(() => + fileList.value.map((value) => { + return value.url; + }) +); + +function handleFilePreview(file) { + initialIndex.value = fileList.value.indexOf(file); + previewShow.value = true; +} + +function closePreview() { + previewShow.value = false; +} function handleFileRemove(file, fileList) { formObj.value.files = fileList; @@ -127,6 +161,13 @@ const loading = ref(false); // 琛ㄥ崟妫�鏌ヨ鍒� const rules = reactive({ + cqName: [ + { + required: true, + message: '闂鍚嶇О涓嶈兘涓虹┖', + trigger: 'blur' + } + ], cqDescription: [ { required: true, @@ -182,6 +223,7 @@ const coor = formObj.value.coordinate.split(','); const q = { cId: parseInt(props.clueId), + cqName: formObj.value.cqName, cqDescription: formObj.value.cqDescription, cqStreet: formObj.value.cqStreet, cqAddress: formObj.value.cqAddress, @@ -238,26 +280,34 @@ url: f }); }); - return question; + return { ...question }; } watch( - () => props.show, + () => [props.show, props.question], (val) => { - dialogShow.value = val; - } -); -watch( - () => props.question, - (val) => { - fileList.value = []; - if (val) { - formObj.value = parseFormObj(val); - } else { - formObj.value = {}; + dialogShow.value = val[0]; + if (val[0]) { + fileList.value = []; + if (val[1]) { + formObj.value = parseFormObj(val[1]); + } else { + formObj.value = {}; + } } } ); +// watch( +// () => props.question, +// (val) => { +// fileList.value = []; +// if (val) { +// formObj.value = parseFormObj(val); +// } else { +// formObj.value = {}; +// } +// } +// ); watch(dialogShow, (val) => { emit('update:show', val); }); diff --git a/src/views/overlay-grid/GridLayout.vue b/src/views/overlay-grid/GridLayout.vue index aeb080d..8a65679 100644 --- a/src/views/overlay-grid/GridLayout.vue +++ b/src/views/overlay-grid/GridLayout.vue @@ -1,16 +1,36 @@ <template> - <el-row class="container"> - <el-col :span="4" class="grid-content bg-content"> - <div class="title">缃戞牸鍖栫鐞�</div> - <OptionGridRecord v-model:value="gridRecord"></OptionGridRecord> - <ListGridDetail></ListGridDetail> - <GridCreate - :is-active="dialogVisible" - :is-create="true" - ></GridCreate> + <el-row class="fy-body fy-overlay-container" gutter="0"> + <el-col :span="6"> + <div class="fy-card fy-main"> + <div class="fy-h1">缃戞牸鍖栫鐞�</div> + <div class="fy-flex-row"> + <span>鏂规</span> + <OptionGridRecord + :refresh="newScheme" + v-model:value="gridSchemeId" + ></OptionGridRecord> + <el-button + :disabled="!gridSchemeId" + icon="Search" + type="primary" + @click="getSchemeList" + >鏌ヨ</el-button + > + <SchemeCreate @created="newScheme = !newScheme"></SchemeCreate> + </div> + <ListGridDetail></ListGridDetail> + <GridCreate + :schemeId="gridSchemeId" + :is-active="dialogVisible" + ></GridCreate> + </div> </el-col> - <el-col v-if="gridStore.selectedGrid" :span="4" class="grid-content bg-content-1"> - <GridEditing></GridEditing> + <el-col v-if="gridStore.selectedGrid" :span="4" :offset="14"> + <div class="fy-column-reverse"> + <!-- <div class="fy-card"> --> + <GridEditing></GridEditing> + <!-- </div> --> + </div> </el-col> </el-row> </template> @@ -20,60 +40,31 @@ import OptionGridRecord from './components/OptionGridRecord.vue'; import GridCreate from './components/GridCreate.vue'; import GridEditing from './components/GridEditing.vue'; +import SchemeCreate from './components/SchemeCreate.vue'; import { ref, watch } from 'vue'; import baseMapUtil from '@/components/map/baseMapUtil'; import { onMapMounted } from '@/components/map/baseMap'; -import gridRecordApi from '@/api/gridRecordApi'; +import gridInfoApi from '@/api/grid/gridInfoApi'; import { useGridStore } from '@/stores/grid'; const gridStore = useGridStore(); // 缃戞牸瑙勫垝鏂规id -const gridRecord = ref({ value: '' }); -// 鏂规鍏蜂綋缃戞牸淇℃伅闆嗗悎 +const gridSchemeId = ref(); -const getList = function () { +const newScheme = ref(false) + +// 鑾峰彇鏂规璁板綍 +function getSchemeList() { onMapMounted(() => { - gridRecordApi - .getGridRecordDetail(gridRecord.value) - .then((res) => { - baseMapUtil.clearMap(); - gridStore.setGridList(res); - }); + gridInfoApi.fetchGridList(gridSchemeId.value).then((res) => { + baseMapUtil.clearMap(); + gridStore.setGridList(res); + }); }); -}; +} -watch(gridRecord, getList); +// watch(gridSchemeId, getList); </script> -<style scoped> -.container { - pointer-events: none; -} - -.title { - font-size: var(--el-font-size-large); -} - -.grid-content { - min-width: calc(var(--screen-min-width) / 6); - /* min-width: 180px; */ - border-radius: 4px; - display: flex; - flex-direction: column; - gap: 16px; - padding: 8px 8px; - pointer-events: auto; -} - -.bg-content { - height: 90vh; - background: white; -} - -.bg-content-1 { - background: antiquewhite; - height: 40vh; - margin-left: 8px; -} -</style> +<style scoped></style> diff --git a/src/views/overlay-grid/components/GridCreate.vue b/src/views/overlay-grid/components/GridCreate.vue index 45f2caa..6152df0 100644 --- a/src/views/overlay-grid/components/GridCreate.vue +++ b/src/views/overlay-grid/components/GridCreate.vue @@ -1,8 +1,19 @@ <template> <div> - <el-button type="primary" @click="createGrid">鏂板缓缃戞牸</el-button> + <el-button + :disabled="!gridStore.hasScheme" + type="primary" + @click="createGrid" + >鏂板缓缃戞牸</el-button + > </div> - <el-dialog v-model="dialogVisible" title="Tips" width="30%"> + <el-dialog + v-model="dialogVisible" + title="鏂板缓缃戞牸" + width="600px" + :close-on-click-modal="false" + :close-on-press-escape="false" + > <el-form :inline="false" :model="formObj" @@ -39,6 +50,8 @@ import { useGridStore } from '@/stores/grid'; import mapGrid from '@/components/map/mapGrid'; import baseMapUtil from '@/components/map/baseMapUtil'; +import gridInfoApi from '@/api/grid/gridInfoApi'; +import { getGridRecord } from '@/model/gridRecord'; const gridStore = useGridStore(); @@ -56,15 +69,11 @@ }; const props = defineProps({ - //鍩烘湰淇℃伅 - formInfo: Object, - //鏄垱寤烘垨鑰呮洿鏂� - isCreate: Boolean, + //缃戞牸鏂规id + schemeId: String, // isActive: Boolean }); - -const emit = defineEmits(['onSubmit', 'onCancel']); const { formObj, formRef, edit, active, onSubmit, onCancel } = useFormConfirm({ @@ -88,60 +97,43 @@ ] }); -// 鍒涘缓 -async function create() { - // loading.value = true; - // return sceneApi - // .createScene(formObj.value) - // .then((res) => { - // console.log(res); - // }) - // .finally(() => { - // loading.value = false; - // }); -} - -// 鏇存柊 -async function update() { - // loading.value = true; - // return sceneApi - // .updateScene(formObj.value) - // .then((res) => { - // console.log(res); - // }) - // .finally(() => { - // loading.value = false; - // }); -} - function submit() { - const newRecord = { - gId: '1', - gType: 0, - gName: formObj.value.gName, - gSide: tempOverlays.getPath(), - overlays: tempOverlays + const gridInfo = { + gsId: props.schemeId, + giName: formObj.value.gName, + giSide: tempOverlays.getPath().join(';') }; - gridStore.addGrid(newRecord); - emit('onSubmit', newRecord); - dialogVisible.value = false; + loading.value = true; + return gridInfoApi + .createGrid(gridInfo) + .then((res) => { + const newRecord = { + ...res, + overlays: tempOverlays + }; - return props.isCreate ? create() : update(); + gridStore.addGrid(getGridRecord(newRecord)); + dialogVisible.value = false; + }) + // .catch((err) => { + // return err; + // }) + .finally(() => (loading.value = false)); } + function cancel() { - emit('onCancel'); baseMapUtil.removeView(tempOverlays); dialogVisible.value = false; } -watch( - () => props.formInfo, - (nValue) => { - formObj.value = nValue; - }, - { immediate: false } -); +// watch( +// () => props.formInfo, +// (nValue) => { +// formObj.value = nValue; +// }, +// { immediate: false } +// ); watch(dialogVisible, (nValue) => { active.value = nValue; diff --git a/src/views/overlay-grid/components/GridEditing.vue b/src/views/overlay-grid/components/GridEditing.vue index 3d7d5d1..619aae4 100644 --- a/src/views/overlay-grid/components/GridEditing.vue +++ b/src/views/overlay-grid/components/GridEditing.vue @@ -1,18 +1,53 @@ <template> - <div>褰撳墠鎿嶄綔缃戞牸: {{ selectedGrid.gName }}</div> - <div>缃戞牸缂栧彿锛歿{ selectedGrid.gId }}</div> - <div>缃戞牸椤剁偣锛�</div> - <div v-for="(item, index) in selectedGrid.gSide" :key="index"> - {{ item }} - </div> - <div class="btn-group"> - <el-button @click="startOrCompleteEdit">{{ - isEdit ? '淇濆瓨缂栬緫' : '寮�濮嬬紪杈�' - }}</el-button> - <el-button :disabled="!isEdit" @click="cancelEdit" - >鍙栨秷缂栬緫</el-button - > - </div> + <CloseButton @close="closeEdit"> + <div class="fy-card"> + <div class="fy-h2">姝e湪缂栬緫缃戞牸</div> + <div class="fy-main"> + <el-form + label-position="left" + :rules="rules" + :model="selectedGrid" + ref="formRef" + > + <!-- <el-form-item label="缂栧彿" prop="id"> + <div>{{ selectedGrid.id }}</div> + </el-form-item> --> + <el-form-item label="鍚嶇О" prop="name"> + <el-input + v-model="selectedGrid.name" + placeholder="璇疯緭鍏ョ綉鏍煎悕绉�" + clearable + disabled + ></el-input> + </el-form-item> + <el-form-item label="椤剁偣" prop="sides"> + <el-scrollbar height="100px" class="fy-main-border"> + <div + class="list-wrapper" + v-for="(item, index) in selectedGrid.sides" + :key="index" + > + {{ `${index + 1}. ${item}` }} + </div> + </el-scrollbar> + </el-form-item> + </el-form> + <div class="btn-group"> + <el-button + @click="startOrCompleteEdit" + :loading="loading" + >{{ isEdit ? '淇濆瓨缂栬緫' : '寮�濮嬬紪杈�' }}</el-button + > + <el-button + type="danger" + :disabled="!isEdit" + @click="cancelEdit" + >鍙栨秷缂栬緫</el-button + > + </div> + </div> + </div> + </CloseButton> </template> <script> @@ -30,7 +65,8 @@ }, data() { return { - editing: false + editing: false, + loading: false }; }, computed: { @@ -41,13 +77,18 @@ 'openGridEdit', 'closeGridEdit', 'saveSelectedGrid', - 'quitSelectedGrid' + 'quitSelectedGrid', + 'clearSelect' ]), // 寮�濮嬫垨瀹屾垚淇濆瓨缂栬緫缃戞牸澶氳竟褰� startOrCompleteEdit() { if (this.isEdit) { - this.saveSelectedGrid(); - this.closeGridEdit(); + this.loading = true; + this.saveSelectedGrid() + .then(() => { + this.closeGridEdit(); + }) + .finally(() => (this.loading = false)); } else { this.openGridEdit(); } @@ -56,12 +97,27 @@ cancelEdit() { this.quitSelectedGrid(); this.closeGridEdit(); + }, + // 鍏抽棴缂栬緫鐣岄潰 + closeEdit() { + this.cancelEdit(); + this.clearSelect(); } } }; </script> <style scoped> +.wrapper { + /* position: relative; + background: antiquewhite; + padding-right: 10px; */ +} .btn-group { display: flex; } -</style> \ No newline at end of file + +.list-wrapper { + width: 100%; + /* background-color: var(--el-bg-color-page); */ +} +</style> diff --git a/src/views/overlay-grid/components/ListGridDetail.vue b/src/views/overlay-grid/components/ListGridDetail.vue index 1ac26cf..d08b3d9 100644 --- a/src/views/overlay-grid/components/ListGridDetail.vue +++ b/src/views/overlay-grid/components/ListGridDetail.vue @@ -14,8 +14,8 @@ v-if="!item.delete" > <div style="display: flex; gap: 8px"> - <div>{{ item.gName }}</div> - <div>{{ item.gSide.length + '/4' }}</div> + <div>{{ item.name }}</div> + <div>{{ item.sides.length + '/4' }}</div> </div> <Transition> <el-button @@ -83,7 +83,7 @@ .list-container { /* background-color: antiquewhite; */ padding: initial; - height: 50vh; + height: 60vh; overflow: auto; overflow-x: hidden; border: var(--el-border); diff --git a/src/views/overlay-grid/components/OptionGridRecord.vue b/src/views/overlay-grid/components/OptionGridRecord.vue index ce725c9..a37eef8 100644 --- a/src/views/overlay-grid/components/OptionGridRecord.vue +++ b/src/views/overlay-grid/components/OptionGridRecord.vue @@ -2,13 +2,13 @@ <el-select v-model="selectedOptions" placeholder="缃戞牸鍖栬褰�" - style="max-width: 150px" + style="width: 150px" > <el-option v-for="s in options" - :key="s.value" - :label="s.label" - :value="s" + :key="s.gsId" + :label="s.gsName" + :value="s.gsId" /> </el-select> </template> @@ -16,17 +16,14 @@ <script> // 缃戞牸鍖栨柟妗堣褰曢�夐」 -import gridRecordApi from '@/api/gridRecordApi'; +import gridSchemeApi from '@/api/grid/gridSchemeApi'; export default { props: { - // 鏄惁鍦ㄩ閫夐」澶勬坊鍔犫�滃叏閮ㄢ�濋�夐」 - // allOption: { - // type: Boolean, - // default: true, - // }, + // 鍒锋柊涓嬫媺鍒楄〃 + refresh: Boolean, // 杩斿洖缁撴灉 - value: Object, + value: Number }, data() { return { @@ -35,18 +32,29 @@ }; }, watch: { - selectedOptions: { - handler(val) { - this.$emit('update:value', val); - }, - deep: true, + // selectedOptions: { + // handler(val) { + // this.$emit('update:value', val); + // }, + // deep: true + // }, + selectedOptions(nVal) { + this.$emit('update:value', nVal); }, + refresh() { + this.getOptions(true); + } }, methods: { - getOptions() { - gridRecordApi.getGridRecords().then((res) => { - this.options = res; - this.selectedOptions = res[0]; + getOptions(newScheme) { + gridSchemeApi.fetchAllSchemes().then((res) => { + if (res.length > 0) { + this.options = res; + this.selectedOptions = newScheme + ? res[res.length - 1].gsId + : res[0].gsId; + // this.selectedOptions = res[0].gsId; + } }); } }, diff --git a/src/views/overlay-grid/components/SchemeCreate.vue b/src/views/overlay-grid/components/SchemeCreate.vue new file mode 100644 index 0000000..a6da646 --- /dev/null +++ b/src/views/overlay-grid/components/SchemeCreate.vue @@ -0,0 +1,101 @@ +<template> + <el-button icon="Plus" type="success" plain @click="openDialog" + >鏂板缓鏂规</el-button + > + <el-dialog + v-model="dialogShow" + width="600px" + :close-on-click-modal="false" + :close-on-press-escape="false" + destroy-on-close + > + <template #header> + <span> 鏂板缓鏂规</span> + </template> + <el-form + label-width="90px" + label-position="left" + :rules="rules" + :model="formObj" + ref="formRef" + > + <el-form-item label="鏂规鍚嶇О" prop="gsName"> + <el-input + style="width: 400px" + v-model="formObj.gsName" + placeholder="璇疯緭鍏ユ柟妗堝悕绉�" + ></el-input> + </el-form-item> + <el-form-item label="鏂规鎻忚堪" prop="gsDescription"> + <el-input + v-model="formObj.gsDescription" + type="textarea" + placeholder="璇疯緭鍏ユ柟妗堟弿杩�" + ></el-input> + </el-form-item> + <el-form-item label="鍒涘缓浜�" prop="gsCreatorName"> + <el-input + style="width: 200px" + v-model="formObj.gsCreatorName" + placeholder="璇疯緭鍏ュ垱寤轰汉" + ></el-input> + </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> +</template> + +<script setup> +import { reactive, ref, watch } from 'vue'; +import { useFormConfirm } from '@/composables/formConfirm'; +import gridSchemeApi from '@/api/grid/gridSchemeApi'; + +const emit = defineEmits(['created']); + +const rules = reactive({ + gsName: [ + { + required: true, + message: '鏂规鍚嶇О涓嶈兘涓虹┖', + trigger: 'blur' + } + ] +}); + +const { formObj, formRef, edit, onSubmit, onCancel } = useFormConfirm( + { + submit: { + do: submit + }, + cancel: { + do: cancel + } + } +); + +const dialogShow = ref(false); +function openDialog() { + dialogShow.value = true; +} + +function submit() { + return gridSchemeApi.createScheme(formObj.value).then(() => { + // clear() + emit('created') + dialogShow.value = false; + }); +} + +function cancel() { + dialogShow.value = false; +} +</script> diff --git a/vite.config.js b/vite.config.js index ea3fe35..56719e5 100644 --- a/vite.config.js +++ b/vite.config.js @@ -26,5 +26,8 @@ alias: { '@': fileURLToPath(new URL('./src', import.meta.url)) } + }, + server: { + host: '0.0.0.0' } }); -- Gitblit v1.9.3