station_a.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. <template>
  2. <n-divider dashed title-placement="left">测站点</n-divider>
  3. <div class="hc-layout-box">
  4. <n-card class="hc-card-overflow-p-box" :segmented="{content: true}">
  5. <template #header>
  6. <div class="hc-card-header flex items-center">
  7. <div class="w-60">
  8. <n-input v-model:value="searchForm.name" type="text" placeholder="请输入测站点或关键字进行搜索" clearable/>
  9. </div>
  10. <n-button type="primary" class="px-5 ml-3" @click="searchChange">搜索</n-button>
  11. <n-popover trigger="hover" :disabled="!bubbleVal || !btn_add?.textInfo" v-if="btn_add">
  12. <template #trigger>
  13. <n-button type="primary" strong secondary class="px-5 ml-10" @click="AddRowClick">新增</n-button>
  14. </template>
  15. <span>{{btn_add?.textInfo}}</span>
  16. </n-popover>
  17. <n-popover trigger="hover" :disabled="!bubbleVal || !btn_import?.textInfo" v-if="btn_import">
  18. <template #trigger>
  19. <n-button type="primary" strong secondary class="px-5 ml-3" @click="importModalClick">导入</n-button>
  20. </template>
  21. <span>{{btn_import?.textInfo}}</span>
  22. </n-popover>
  23. <n-popover trigger="hover" :disabled="!bubbleVal || !btn_export?.textInfo" v-if="btn_export">
  24. <template #trigger>
  25. <n-button type="primary" strong secondary class="px-5 ml-3" @click="exportModalClick">导出</n-button>
  26. </template>
  27. <span>{{btn_export?.textInfo}}</span>
  28. </n-popover>
  29. </div>
  30. </template>
  31. <template #header-extra>
  32. <HcTabs :datas="tabsTypeData" :keys="tabsTypeKey" @change="tabsTypeChange"/>
  33. </template>
  34. <div v-if="tabsTypeKey==='1'">
  35. <n-data-table :columns="traverseColumns" :data="traverseTable" :pagination="false" :row-key="row => row.name" :single-line="false" striped/>
  36. </div>
  37. <div v-if="tabsTypeKey==='0'">
  38. <n-data-table :columns="levelColumns" :data="levelTable" :pagination="false" :row-key="row => row.name" :single-line="false" striped/>
  39. </div>
  40. <template #action>
  41. <HcPage :pages="searchForm" @change="pageChange"/>
  42. </template>
  43. </n-card>
  44. </div>
  45. <!--新增/编辑 弹框-->
  46. <n-modal v-model:show="showRowModal">
  47. <n-card class="w-750" :title="rowModalTitle()" :segmented="{content: true}">
  48. <n-form ref="formRowRef" :model="formRowValue" :rules="rulesRow" label-placement="left" label-width="auto" size="large">
  49. <n-form-item label="点名称" path="name">
  50. <n-input class="flex-1" v-model:value="formRowValue.name" placeholder="请输入点名称"/>
  51. </n-form-item>
  52. <n-form-item label="X坐标(m)" path="x" v-if="tabsTypeKey === '1'">
  53. <n-input class="flex-1" v-model:value="formRowValue.x" placeholder="请输入X坐标(m)"/>
  54. </n-form-item>
  55. <n-form-item label="Y坐标(m)" path="y" v-if="tabsTypeKey === '1'">
  56. <n-input class="flex-1" v-model:value="formRowValue.y" placeholder="请输入Y坐标(m)"/>
  57. </n-form-item>
  58. <n-form-item label="高程(m)" path="h">
  59. <n-input class="flex-1" v-model:value="formRowValue.h" placeholder="请输入高程(m)"/>
  60. </n-form-item>
  61. <n-form-item label="等级">
  62. <n-select class="flex-1" v-model:value="formRowValue.level" :options="personData" placeholder="请选择等级"/>
  63. </n-form-item>
  64. <n-form-item label="备注">
  65. <n-input v-model:value="formRowValue.remark" placeholder="请输入文字说明" type="textarea" :autosize="{minRows: 3,maxRows: 5}"/>
  66. </n-form-item>
  67. </n-form>
  68. <template #action>
  69. <div class="text-center">
  70. <n-button class="px-5" @click="showRowModal = false">取消</n-button>
  71. <n-button type="primary" class="px-5 ml-4" :loading="saveFormLoading" @click="saveFormClick">保存</n-button>
  72. </div>
  73. </template>
  74. </n-card>
  75. </n-modal>
  76. <!--导入 弹框-->
  77. <n-modal v-model:show="showImportModal">
  78. <n-card class="w-750" :title="'导入' + getModalTitle()" :segmented="{content: true}">
  79. <div class="hc-import-modal-box">
  80. <div class="tip-box">
  81. <span>请先下载导入模板(</span>
  82. <a class="text-link" href="https://bladex-test-info.oss-cn-chengdu.aliyuncs.com//upload/20220614/a4b08ea228dbf74db1c049c4d878fbe7.xlsx" target="_blank" v-if="tabsTypeKey==='1'">导线点导入模板</a>
  83. <a class="text-link" href="https://bladex-test-info.oss-cn-chengdu.aliyuncs.com//upload/20220629/5fa2abeaa1ad553ee4adf64118df4e2a.xlsx" target="_blank" v-if="tabsTypeKey==='0'">水准点导入模板</a>
  84. <span> ),按模板样式编辑测站点后,再点击"选择文件"按钮选择编辑好的文件,并点击底部的"确认导入"按钮即可导入成功!</span>
  85. </div>
  86. <div class="upload-box">
  87. <n-upload ref="uploadRef" :action="action" :headers="getTokenHeader()" :data="upData" :max="1" :accept="accept" :default-upload="false" multiple @change="handleUploadChange" @finish="uploadFinish">
  88. <n-button type="primary" class="px-4">选择文件</n-button>
  89. </n-upload>
  90. </div>
  91. <div class="text-orange">导入模板格式示例:</div>
  92. <div class="demo-img-box" v-if="tabsTypeKey==='1'">
  93. <img src="../../assets/view/152221@2x.png" alt="">
  94. </div>
  95. <div class="demo-img-box" v-if="tabsTypeKey==='0'">
  96. <img src="../../assets/view/152211@2x.png" alt="">
  97. </div>
  98. </div>
  99. <template #action>
  100. <div class="text-center">
  101. <n-button class="px-4" @click="showImportModal = false">取消</n-button>
  102. <n-button type="primary" :disabled="!fileListLength" :loading="importLoading" class="px-4 ml-4" @click="handleImportClick">确认导入</n-button>
  103. </div>
  104. </template>
  105. </n-card>
  106. </n-modal>
  107. </template>
  108. <script setup>
  109. import {ref,watch,onMounted} from "vue";
  110. import {useAppStore} from "~src/store/index";
  111. import HcTabs from "~com/plugins/naive/HcTabs.vue"
  112. import HcPage from "~com/plugins/naive/HcPage.vue"
  113. import {renderTableEditDelButton} from "~src/plugins/renderele";
  114. import {getTokenHeader} from '~src/api/request/header';
  115. import station from '~api/gauge/station';
  116. import {download} from "~src/utils/lib/tools";
  117. //初始变量
  118. const useAppState = useAppStore()
  119. const projectId = ref(useAppState.getProjectId);
  120. const contractId = ref(useAppState.getContractId);
  121. //按钮气泡开关
  122. const bubbleVal = ref(useAppState.getBubble);
  123. //监听
  124. watch(() => [
  125. useAppState.getProjectId,
  126. useAppState.getContractId,
  127. useAppState.getBubble,
  128. ], ([UserProjectId,UserContractId,Bubble]) => {
  129. projectId.value = UserProjectId
  130. contractId.value = UserContractId
  131. //按钮气泡开关
  132. bubbleVal.value = Bubble
  133. })
  134. //获取气泡数据
  135. const getButtonsVal = (value) => {
  136. return useAppState.getButtonsVal(value)
  137. }
  138. //气泡数据
  139. const btn_add = ref(getButtonsVal('gauge-station-add'))
  140. const btn_import = ref(getButtonsVal('gauge-station-import'))
  141. const btn_export = ref(getButtonsVal('gauge-station-export'))
  142. const btn_edit = ref(getButtonsVal('gauge-station-edit'))
  143. const btn_del = ref(getButtonsVal('gauge-station-del'))
  144. //搜索表单
  145. const searchForm = ref({
  146. projectId: projectId.value,
  147. contractId: contractId.value,
  148. name: null, type: '1',
  149. current: 1, size: 20, total: 0
  150. })
  151. //结构类型tab数据和相关处理
  152. const tabsTypeKey = ref('1')
  153. const tabsTypeData = ref([
  154. {key:'0', name: '水准点'},
  155. {key:'1', name: '导线点'}
  156. ]);
  157. const tabsTypeChange = (value) => {
  158. tabsTypeKey.value = value;
  159. searchForm.value.type = value;
  160. searchForm.value.current = 1
  161. getTableData()
  162. }
  163. //渲染完成
  164. onMounted(() => {
  165. getTableData()
  166. })
  167. //新增编辑
  168. const showRowModal = ref(false)
  169. const formRowRef = ref(null)
  170. const formRowValue = ref({
  171. projectId: projectId.value,
  172. contractId: contractId.value,
  173. type: tabsTypeKey.value,
  174. name: '', x: '', y: '', h: '', level: null, remark: null
  175. })
  176. const personData = ref([
  177. {label: "一级", value: "一级"}, {label: "二级", value: "二级"},
  178. {label: "三级", value: "三级"}, {label: "四级", value: "四级"}
  179. ])
  180. const rulesRow = {
  181. name: {
  182. required: true,
  183. trigger: ["blur", "input"],
  184. message: "请输入测站点名称"
  185. },
  186. x: {
  187. required: true,
  188. trigger: ["blur", "input"],
  189. message: "请输入X坐标(m)"
  190. },
  191. y: {
  192. required: true,
  193. trigger: ["blur", "input"],
  194. message: "请输入Y坐标(m)"
  195. },
  196. h: {
  197. required: true,
  198. trigger: ["blur", "input"],
  199. message: "请输入高程(m)"
  200. }
  201. }
  202. //卡片弹窗标题
  203. const rowModalTitle = () => {
  204. let formType = '新增', tabType = '异常了';
  205. if (formRowValue.value.id) {
  206. formType = '编辑'
  207. }
  208. if (tabsTypeKey.value === '1') {
  209. tabType = '导线点'
  210. } else if (tabsTypeKey.value === '0') {
  211. tabType = '水准点'
  212. }
  213. return formType + tabType
  214. }
  215. //导线点的 表格表头
  216. const createTraverseColumns = ({edit,del}) => {
  217. return [
  218. {title: '序号', key: 'num', width: 80, align: 'center',
  219. render(_, index) {
  220. return index + 1
  221. }
  222. },
  223. {title: '测站点名称', key: 'name'},
  224. {title: 'X坐标(m)', key: 'x'},
  225. {title: 'Y坐标(m)', key: 'y'},
  226. {title: '高程(m)', key: 'h'},
  227. {title: '等级', key: 'level'},
  228. {title: '备注', key: 'remark'},
  229. {title: "操作", key: "actions", width: 160, align: 'center',
  230. render(row) {
  231. return renderTableEditDelButton({
  232. bubble: bubbleVal.value,
  233. btn_edit: btn_edit.value,
  234. btn_del: btn_del.value,
  235. edit_event: edit,
  236. del_event: del,
  237. row:row
  238. })
  239. }
  240. }
  241. ];
  242. };
  243. const traverseColumns = createTraverseColumns({
  244. edit(row) {
  245. let form = JSON.parse(JSON.stringify(row));
  246. let mile = ['name', 'x', 'y', 'h', 'level', 'remark']
  247. mile.forEach((key) => {
  248. formRowValue.value[key] = form[key] + '';
  249. })
  250. formRowValue.value['id'] = form.id;
  251. formRowValue.value['projectId'] = projectId.value;
  252. formRowValue.value['contractId'] = contractId.value;
  253. showRowModal.value = true
  254. },
  255. del(row) {
  256. station.delData({
  257. ids: row.id
  258. }).then(({data}) => {
  259. if (data.code === 200) {
  260. window?.$message?.success('删除成功')
  261. getTableData()
  262. } else {
  263. window?.$message?.error('删除失败')
  264. }
  265. })
  266. },
  267. })
  268. const traverseTable = ref([]);
  269. //水准点的 表格表头
  270. const createLevelColumns = ({edit,del}) => {
  271. return [
  272. {title: '序号', key: 'num', width: 80, align: 'center',
  273. render(_, index) {
  274. return index + 1
  275. }
  276. },
  277. {title: '测站点名称', key: 'name'},
  278. {title: '高程(m)', key: 'h'},
  279. {title: '等级', key: 'level'},
  280. {title: '备注', key: 'remark'},
  281. {title: "操作", key: "actions", width: 160, align: 'center',
  282. render(row) {
  283. return renderTableEditDelButton({
  284. bubble: bubbleVal.value,
  285. btn_edit: btn_edit.value,
  286. btn_del: btn_del.value,
  287. edit_event: edit,
  288. del_event: del,
  289. row:row
  290. })
  291. }
  292. }
  293. ];
  294. };
  295. const levelColumns = createLevelColumns({
  296. edit(row) {
  297. let form = JSON.parse(JSON.stringify(row));
  298. let mile = ['name', 'h', 'level', 'remark'];
  299. mile.forEach((key) => {
  300. formRowValue.value[key] = form[key] + '';
  301. })
  302. formRowValue.value['id'] = form.id;
  303. formRowValue.value['projectId'] = projectId.value;
  304. formRowValue.value['contractId'] = contractId.value;
  305. showRowModal.value = true
  306. },
  307. del(row) {
  308. station.delData({
  309. ids: row.id
  310. }).then(({data}) => {
  311. if (data.code === 200) {
  312. window?.$message?.success('删除成功')
  313. getTableData()
  314. } else {
  315. window?.$message?.error('删除失败')
  316. }
  317. })
  318. },
  319. })
  320. //表格数据
  321. const levelTable = ref([]);
  322. //新增
  323. const AddRowClick = () => {
  324. if (tabsTypeKey.value === '0') {
  325. formRowValue.value = {
  326. projectId: projectId.value,
  327. contractId: contractId.value,
  328. type: tabsTypeKey.value,
  329. name: '', h: '', level: null, remark: null
  330. }
  331. } else if (tabsTypeKey.value === '1') {
  332. formRowValue.value = {
  333. projectId: projectId.value,
  334. contractId: contractId.value,
  335. type: tabsTypeKey.value,
  336. name: '', x: '', y: '', h: '', level: null, remark: null
  337. }
  338. }
  339. showRowModal.value = true
  340. }
  341. //保存表单
  342. const saveFormLoading = ref(false)
  343. const saveFormClick = () => {
  344. const form = formRowValue.value
  345. if (!!form.id) {
  346. saveFormLoading.value = true
  347. station.updateSave(formRowValue.value).then(({data}) => {
  348. saveFormLoading.value = false
  349. if (data.code === 200) {
  350. getTableData()
  351. showRowModal.value = false
  352. window?.$message?.success('保存成功')
  353. } else {
  354. window?.$message?.error('保存失败')
  355. }
  356. }).catch(() => {
  357. saveFormLoading.value = false
  358. })
  359. } else {
  360. saveFormLoading.value = true
  361. station.addSave(formRowValue.value).then(({data}) => {
  362. saveFormLoading.value = false
  363. if (data.code === 200) {
  364. getTableData()
  365. showRowModal.value = false
  366. window?.$message?.success('新增成功')
  367. } else {
  368. window?.$message?.error('新增失败')
  369. }
  370. }).catch(() => {
  371. saveFormLoading.value = false
  372. })
  373. }
  374. }
  375. //导入弹窗
  376. const showImportModal = ref(false)
  377. const fileListLength = ref(0);
  378. const uploadRef = ref(null);
  379. const importLoading = ref(false)
  380. const action = '/api/blade-business/dap/import';
  381. const accept = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel';
  382. const upData = ref({
  383. projectId: projectId.value,
  384. contractId: contractId.value,
  385. type: tabsTypeKey.value
  386. })
  387. const importModalClick = () => {
  388. upData.value = {
  389. projectId: projectId.value,
  390. contractId: contractId.value,
  391. type: tabsTypeKey.value
  392. }
  393. showImportModal.value = true
  394. }
  395. const handleUploadChange = (options) => {
  396. fileListLength.value = options.fileList.length;
  397. }
  398. const handleImportClick = () => {
  399. importLoading.value = true
  400. uploadRef.value?.submit();
  401. }
  402. //上传完成
  403. const uploadFinish = ({event}) => {
  404. importLoading.value = false
  405. let res = JSON.parse(event?.target?.response);
  406. if (res.code === 200) {
  407. window?.$message?.success('导入成功')
  408. showImportModal.value = false
  409. getTableData()
  410. } else {
  411. window?.$message?.error(res.msg||'导入失败')
  412. }
  413. }
  414. //卡片弹窗标题
  415. const getModalTitle = () => {
  416. let tabType = '异常了';
  417. if (tabsTypeKey.value === '1') {
  418. tabType = '导线点'
  419. } else if (tabsTypeKey.value === '0') {
  420. tabType = '水准点'
  421. }
  422. return tabType
  423. }
  424. //导出弹窗
  425. const exportModalClick = () => {
  426. window?.$dialog?.warning({
  427. title: "导出数据",
  428. content: "将导出当前所有数据",
  429. positiveText: "确定导出",
  430. negativeText: "取消",
  431. onPositiveClick: () => {
  432. station.getExportExcel({
  433. projectId: projectId.value,
  434. contractId: contractId.value,
  435. type: tabsTypeKey.value,
  436. search: searchForm.value['name'] || ''
  437. }).then(res => {
  438. download(res)
  439. })
  440. }
  441. });
  442. }
  443. //重新搜索数据
  444. const searchChange = () => {
  445. searchForm.value.current = 1
  446. getTableData()
  447. }
  448. //分页被点击
  449. const pageChange = (res) => {
  450. searchForm.value.current = res.current;
  451. searchForm.value.size = res.size;
  452. getTableData()
  453. }
  454. //获取数据
  455. const getTableData = () => {
  456. station.queryListData(searchForm.value).then(({data}) => {
  457. let res = data['data'] || {}
  458. if (tabsTypeKey.value === '0') {
  459. levelTable.value = res['records'] || []
  460. } else if (tabsTypeKey.value === '1') {
  461. traverseTable.value = res['records'] || []
  462. }
  463. searchForm.value.total = res.total || 0
  464. })
  465. }
  466. </script>
  467. <style lang="scss" scoped>
  468. @import '../../styles/gauge/station.scss';
  469. </style>