|
|
@@ -220,7 +220,15 @@
|
|
|
<div
|
|
|
v-if="
|
|
|
taskColumn.apiFrom.apiParameterRules &&
|
|
|
- includesKey(['lonKey', 'latKey', 'outFileType', 'inPrj', 'outPrj'])
|
|
|
+ includesKey([
|
|
|
+ 'lonKey',
|
|
|
+ 'latKey',
|
|
|
+ 'outFileType',
|
|
|
+ 'inPrj',
|
|
|
+ 'outPrj',
|
|
|
+ 'keyType',
|
|
|
+ 'geocodeColumnKeyword',
|
|
|
+ ])
|
|
|
"
|
|
|
>
|
|
|
<template
|
|
|
@@ -228,8 +236,24 @@
|
|
|
:key="index"
|
|
|
>
|
|
|
<el-form-item
|
|
|
- v-if="['lonKey', 'latKey', 'outFileType', 'inPrj', 'outPrj'].includes(rulesItem)"
|
|
|
- :label="rulesItem"
|
|
|
+ v-if="
|
|
|
+ [
|
|
|
+ 'lonKey',
|
|
|
+ 'latKey',
|
|
|
+ 'outFileType',
|
|
|
+ 'inPrj',
|
|
|
+ 'outPrj',
|
|
|
+ 'keyType',
|
|
|
+ 'geocodeColumnKeyword',
|
|
|
+ ].includes(rulesItem)
|
|
|
+ "
|
|
|
+ :label="
|
|
|
+ rulesItem === 'keyType'
|
|
|
+ ? '类型字段'
|
|
|
+ : rulesItem === 'geocodeColumnKeyword'
|
|
|
+ ? '数据列名'
|
|
|
+ : rulesItem
|
|
|
+ "
|
|
|
>
|
|
|
<el-input
|
|
|
v-if="['lonKey', 'latKey'].includes(rulesItem)"
|
|
|
@@ -248,6 +272,45 @@
|
|
|
:value="item.value"
|
|
|
/>
|
|
|
</el-select>
|
|
|
+ <el-select
|
|
|
+ v-if="rulesItem === 'keyType'"
|
|
|
+ v-model="taskColumn.from.c_source_data.keyType"
|
|
|
+ placeholder="非空转空时选择地物类型"
|
|
|
+ :clearable="!isGeocodingTaskKeyTypeReadonly()"
|
|
|
+ filterable
|
|
|
+ :disabled="isGeocodingTaskKeyTypeReadonly()"
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ v-for="item in taskColumn.selectOptions.keyType"
|
|
|
+ :key="'wgn-task-keyType-' + item.value"
|
|
|
+ :label="item.label"
|
|
|
+ :value="item.value"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ <el-input
|
|
|
+ v-if="rulesItem === 'geocodeColumnKeyword' && isTaskGeocodeZipForColumnInput"
|
|
|
+ v-model="taskColumn.from.c_source_data.geocodeColumnKeyword"
|
|
|
+ placeholder="zip 内含多个表格时请手动输入列名(与各表表头一致)"
|
|
|
+ clearable
|
|
|
+ />
|
|
|
+ <el-select
|
|
|
+ v-if="rulesItem === 'geocodeColumnKeyword' && !isTaskGeocodeZipForColumnInput"
|
|
|
+ v-model="taskColumn.from.c_source_data.geocodeColumnKeyword"
|
|
|
+ placeholder="请先上传 CSV / XLSX,将自动读取表头"
|
|
|
+ clearable
|
|
|
+ filterable
|
|
|
+ :disabled="
|
|
|
+ !taskColumn.selectOptions.geocodeColumnKeyword ||
|
|
|
+ !taskColumn.selectOptions.geocodeColumnKeyword.length
|
|
|
+ "
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ v-for="item in taskColumn.selectOptions.geocodeColumnKeyword"
|
|
|
+ :key="'wgn-task-geocol-' + item.value"
|
|
|
+ :label="item.label"
|
|
|
+ :value="item.value"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
</el-form-item>
|
|
|
</template>
|
|
|
</div>
|
|
|
@@ -284,6 +347,7 @@
|
|
|
|
|
|
<script>
|
|
|
import { ElNotification } from "element-plus";
|
|
|
+import * as XLSX from "xlsx";
|
|
|
import api from "@/api/content";
|
|
|
export default {
|
|
|
name: "微功能服务",
|
|
|
@@ -387,6 +451,14 @@ export default {
|
|
|
},
|
|
|
// 其他参数
|
|
|
selectOptions: {
|
|
|
+ keyType: [
|
|
|
+ { value: "地址", label: "地址" },
|
|
|
+ { value: "村居", label: "村居" },
|
|
|
+ { value: "街镇", label: "街镇" },
|
|
|
+ { value: "区县", label: "区县" },
|
|
|
+ { value: "要素ID", label: "要素ID" },
|
|
|
+ ],
|
|
|
+ geocodeColumnKeyword: [],
|
|
|
// 单位
|
|
|
unit: [
|
|
|
{
|
|
|
@@ -456,8 +528,20 @@ export default {
|
|
|
},
|
|
|
// 搜索微功能服务的防抖定时器
|
|
|
searchTimeout: null,
|
|
|
+ /** 最近一次任务上传的原始文件,用于先上传后切换任务类型时补解析表头 */
|
|
|
+ taskUploadRawFile: null,
|
|
|
};
|
|
|
},
|
|
|
+ computed: {
|
|
|
+ /** 任务源文件为 zip(多表打包)时,数据列名改用手动输入 */
|
|
|
+ isTaskGeocodeZipForColumnInput() {
|
|
|
+ const n =
|
|
|
+ (this.taskUploadRawFile && this.taskUploadRawFile.name) ||
|
|
|
+ this.taskColumn.from.c_source_file_name ||
|
|
|
+ "";
|
|
|
+ return String(n).toLowerCase().endsWith(".zip");
|
|
|
+ },
|
|
|
+ },
|
|
|
mounted() {
|
|
|
this.dmsDataProxy = systemConfig.dmsDataProxy;
|
|
|
// 任务负责人默认为当前登录用户
|
|
|
@@ -467,6 +551,24 @@ export default {
|
|
|
this.searchServerList();
|
|
|
},
|
|
|
methods: {
|
|
|
+ /** 任务类型为「文件地名地址查询」时,类型字段固定为地址且不可改 */
|
|
|
+ isGeocodingTaskKeyTypeReadonly() {
|
|
|
+ const label = this.$getDmsTypes("yzt_task_type", this.taskColumn.from.c_type);
|
|
|
+ return label === "文件地名地址查询";
|
|
|
+ },
|
|
|
+ syncKeyTypeForGeocodingTask() {
|
|
|
+ if (!this.isGeocodingTaskKeyTypeReadonly()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const pr = this.taskColumn.apiFrom.apiParameterRules;
|
|
|
+ if (!Array.isArray(pr) || !pr.includes("keyType")) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (!this.taskColumn.from.c_source_data) {
|
|
|
+ this.taskColumn.from.c_source_data = {};
|
|
|
+ }
|
|
|
+ this.taskColumn.from.c_source_data.keyType = "地址";
|
|
|
+ },
|
|
|
includesKey(keys) {
|
|
|
let hasKey = false;
|
|
|
keys.forEach((key) => {
|
|
|
@@ -477,6 +579,7 @@ export default {
|
|
|
return hasKey;
|
|
|
},
|
|
|
handleTCUpload(emit) {
|
|
|
+ this.taskUploadRawFile = emit.file;
|
|
|
// 上传任务文件
|
|
|
let formData = new FormData();
|
|
|
formData.append("file", emit.file);
|
|
|
@@ -489,12 +592,15 @@ export default {
|
|
|
if (res.code === 200) {
|
|
|
this.taskColumn.from.c_source_file_name = emit.file.name;
|
|
|
this.taskColumn.from.c_source_file = res.content;
|
|
|
+ this.refreshTaskGeocodeColumns(emit.file);
|
|
|
+ this.syncKeyTypeForGeocodingTask();
|
|
|
ElNotification.success({
|
|
|
title: "成功",
|
|
|
message: "上传任务文件成功",
|
|
|
offset: 80,
|
|
|
});
|
|
|
} else {
|
|
|
+ this.taskUploadRawFile = null;
|
|
|
ElNotification.error({
|
|
|
title: "失败",
|
|
|
message: "上传任务文件失败" + res.msg,
|
|
|
@@ -503,6 +609,7 @@ export default {
|
|
|
}
|
|
|
})
|
|
|
.catch((e) => {
|
|
|
+ this.taskUploadRawFile = null;
|
|
|
ElNotification.error({
|
|
|
title: "失败",
|
|
|
message: "上传任务文件失败" + e,
|
|
|
@@ -540,6 +647,15 @@ export default {
|
|
|
);
|
|
|
// 接口路径
|
|
|
this.taskColumn.apiFrom.apiUrl = apiInfo.c_url;
|
|
|
+ const pr = this.taskColumn.apiFrom.apiParameterRules;
|
|
|
+ if (
|
|
|
+ pr &&
|
|
|
+ pr.includes("geocodeColumnKeyword") &&
|
|
|
+ this.taskUploadRawFile
|
|
|
+ ) {
|
|
|
+ this.refreshTaskGeocodeColumns(this.taskUploadRawFile);
|
|
|
+ }
|
|
|
+ this.syncKeyTypeForGeocodingTask();
|
|
|
} else {
|
|
|
this.taskColumn.apiFrom.apiDescription = "";
|
|
|
this.taskColumn.apiFrom.apiParameterRules = [];
|
|
|
@@ -553,7 +669,7 @@ export default {
|
|
|
})
|
|
|
.catch((e) => {
|
|
|
this.taskColumn.apiFrom.apiDescription = "";
|
|
|
- this.taskColumn.apiFrom.apiParameterRules = "";
|
|
|
+ this.taskColumn.apiFrom.apiParameterRules = [];
|
|
|
ElNotification.error({
|
|
|
title: "失败",
|
|
|
message: "获取任务参数失败" + e,
|
|
|
@@ -561,6 +677,93 @@ export default {
|
|
|
});
|
|
|
});
|
|
|
this.taskColumn.from.c_source_data = {};
|
|
|
+ this.taskColumn.selectOptions.geocodeColumnKeyword = [];
|
|
|
+ }
|
|
|
+ },
|
|
|
+ parseCsvHeaderLine(line) {
|
|
|
+ const out = [];
|
|
|
+ let cur = "";
|
|
|
+ let inq = false;
|
|
|
+ for (let i = 0; i < line.length; i++) {
|
|
|
+ const c = line[i];
|
|
|
+ if (c === '"') {
|
|
|
+ inq = !inq;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (!inq && c === ",") {
|
|
|
+ out.push(cur.trim());
|
|
|
+ cur = "";
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ cur += c;
|
|
|
+ }
|
|
|
+ out.push(cur.trim());
|
|
|
+ return out.filter((h) => h.length > 0);
|
|
|
+ },
|
|
|
+ async refreshTaskGeocodeColumns(file) {
|
|
|
+ const rules = this.taskColumn.apiFrom.apiParameterRules;
|
|
|
+ if (!rules || !rules.includes("geocodeColumnKeyword")) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (!this.taskColumn.from.c_source_data) {
|
|
|
+ this.taskColumn.from.c_source_data = {};
|
|
|
+ }
|
|
|
+ this.taskColumn.from.c_source_data.geocodeColumnKeyword = "";
|
|
|
+ this.taskColumn.selectOptions.geocodeColumnKeyword = [];
|
|
|
+ const raw = file && (file.raw || file);
|
|
|
+ if (!raw || !raw.name) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const name = String(raw.name).toLowerCase();
|
|
|
+ if (name.endsWith(".zip")) {
|
|
|
+ ElNotification.info({
|
|
|
+ title: "数据列名",
|
|
|
+ message: "zip 包请在「数据列名」中手动填写与各 xlsx 表头一致的列名",
|
|
|
+ offset: 80,
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ if (name.endsWith(".csv")) {
|
|
|
+ const text = await raw.text();
|
|
|
+ const firstLine = (text.split(/\r?\n/).find((l) => l.trim().length > 0) || "").trim();
|
|
|
+ if (!firstLine) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const headers = this.parseCsvHeaderLine(firstLine);
|
|
|
+ this.taskColumn.selectOptions.geocodeColumnKeyword = headers.map((h) => ({
|
|
|
+ value: h,
|
|
|
+ label: h,
|
|
|
+ }));
|
|
|
+ ElNotification.success({
|
|
|
+ title: "表头",
|
|
|
+ message: "已解析 CSV 表头,共 " + headers.length + " 列",
|
|
|
+ offset: 80,
|
|
|
+ });
|
|
|
+ } else if (name.endsWith(".xlsx") || name.endsWith(".xls")) {
|
|
|
+ const buf = await raw.arrayBuffer();
|
|
|
+ const wb = XLSX.read(buf, { type: "array" });
|
|
|
+ const sheetName = wb.SheetNames[0];
|
|
|
+ const sheet = wb.Sheets[sheetName];
|
|
|
+ const rows = XLSX.utils.sheet_to_json(sheet, { header: 1, defval: "" });
|
|
|
+ const headers = (rows[0] || []).map((c) => String(c).trim()).filter((c) => c.length > 0);
|
|
|
+ this.taskColumn.selectOptions.geocodeColumnKeyword = headers.map((h) => ({
|
|
|
+ value: h,
|
|
|
+ label: h,
|
|
|
+ }));
|
|
|
+ ElNotification.success({
|
|
|
+ title: "表头",
|
|
|
+ message: "已解析 Excel 首行表头,共 " + headers.length + " 列",
|
|
|
+ offset: 80,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ console.error(e);
|
|
|
+ ElNotification.warning({
|
|
|
+ title: "表头解析",
|
|
|
+ message: "解析表头失败,请确认上传为 CSV 或 XLSX",
|
|
|
+ offset: 80,
|
|
|
+ });
|
|
|
}
|
|
|
},
|
|
|
// 搜索微功能服务
|
|
|
@@ -635,6 +838,7 @@ export default {
|
|
|
// 表单验证
|
|
|
this.$refs.taskFormRef.validate((valid) => {
|
|
|
if (valid) {
|
|
|
+ this.syncKeyTypeForGeocodingTask();
|
|
|
let content = this.taskColumn.from;
|
|
|
content.title =
|
|
|
this.$moment(new Date()).format("YYMMDD_HHmm") +
|