| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825 |
- <template>
- <!-- 唯一根节点:el-card -->
- <el-card class="el-content-wrap mb-3px" shadow="never">
- <!-- 标题 + 提示 -->
- <template v-if="title" slot="header">
- <div class="flex items-center">
- <span class="text-16px font-700">{{ title }}</span>
- <el-tooltip v-if="message" effect="dark" placement="right">
- <template slot="content">
- <div class="max-w-200px">{{ message }}</div>
- </template>
- <i class="el-icon-question ml-5px" style="font-size: 14px" />
- </el-tooltip>
- </div>
- </template>
- <!-- 原 content-wrap 的 slot 内容 -->
- <el-row class="mb-10px">
- <template v-for="btn in dynamicButtons">
- <el-button
- v-if="!btn.ifHide"
- :key="btn.id"
- type="primary"
- size="small"
- @click="handleDynamicButtonClick(btn)"
- >
- {{ btn.buttonName }}
- </el-button>
- </template>
- <el-button size="small" type="danger" @click="AllConditionReset">
- <i class="el-icon-refresh mr-5px" style="font-size: 14px" />
- 全条件重置
- </el-button>
- <el-button size="small" type="primary" @click="Export">
- <i class="el-icon-download mr-5px" style="font-size: 14px" />
- 导出
- </el-button>
- <el-button
- size="small"
- type="success"
- :loading="exportLoading"
- @click="ExportAll"
- >
- <i class="el-icon-download mr-5px" style="font-size: 14px" />
- 导出全部
- </el-button>
- <el-button size="small" @click="handleBack">
- <i class="el-icon-arrow-left mr-5px" style="font-size: 14px" />
- 返回
- </el-button>
- </el-row>
- <!-- 表格 -->
- <el-table
- id="table_excel"
- ref="tableRef"
- v-loading="loading"
- :data="list"
- stripe
- border
- size="small"
- max-height="calc(100vh - 230px)"
- show-overflow-tooltip
- show-summary
- :summary-method="getSummaries"
- @selection-change="handleSelectionChange"
- @header-dragend="handleResize"
- >
- <el-table-column
- v-if="showMultipleList.length"
- type="selection"
- width="55"
- />
- <el-table-column type="index" width="55" align="center" />
- <template v-for="(item, i) in queryData">
- <el-table-column
- v-if="!item.ifHide"
- :key="i"
- :label="item.columnComment"
- :prop="item.columnComment"
- align="center"
- :min-width="item.javaField || ''"
- :sortable="false"
- show-overflow-tooltip
- >
- <template slot="header">
- <div class="mr-5px flex items-center">
- <!-- 排序图标 -->
- <div v-show="item.ifSort" class="mr-5px flex flex-col gap-0">
- <i
- class="el-icon-caret-top"
- style="font-size: 15px; cursor: pointer"
- :class="{
- 'is-sort':
- currentSortField === item.columnComment &&
- currentSortDirection === 'asc',
- }"
- @click="handleSort(item.columnComment, 'asc')"
- />
- <i
- ref=""
- class="el-icon-caret-bottom -mt-1.2"
- style="font-size: 15px; cursor: pointer"
- :class="{
- 'is-sort':
- currentSortField === item.columnComment &&
- currentSortDirection === 'desc',
- }"
- @click="handleSort(item.columnComment, 'desc')"
- />
- </div>
- <span>{{ item.columnComment }}</span>
- <!-- 列过滤 -->
- <FilterColumnInQuery
- v-if="item.listOperationResult"
- :label="item.columnComment"
- :prop="item.columnName"
- :filter-list="queryData"
- :query-id="$route.query.id"
- :filter-list-key="item.columnName"
- order-type="queryManage"
- :param-list="queryParamList"
- :active-filters="customFilters"
- :html-type="item.htmlType"
- :dict-type="item.dictType"
- :is-clear="isClear"
- @select-data="
- (data, field, htmlType) =>
- filterData(data, field, htmlType, item)
- "
- >
- <template slot="reference">
- <div
- class="flex items-center justify-center text-gray-600"
- :class="{ 'has-filter': hasFilter(item.columnName) }"
- >
- <svg-icon
- icon-class="search"
- class="ml-2px"
- style="font-size: 14px; cursor: pointer"
- />
- </div>
- </template>
- </FilterColumnInQuery>
- </div>
- </template>
- <template slot-scope="{ row }">
- <div
- :class="{ active: item.example }"
- @click="
- pathChange(item.example, row[item.columnComment], item, row)
- "
- >
- <dict-tag
- v-if="
- isDict(item.columnComment) &&
- ![undefined, null].includes(row[item.columnComment])
- "
- :type="isDict(item.columnComment)"
- :value="row[item.columnComment]"
- />
- <span
- v-else-if="
- row[item.columnComment] && isDateTime(item.columnComment)
- "
- >
- {{ formatToDateTime(row[item.columnComment]) }}
- </span>
- <span v-else>{{ row[item.columnComment] }}</span>
- </div>
- </template>
- </el-table-column>
- </template>
- </el-table>
- <!-- 分页 -->
- <pagination
- v-show="total > 0"
- :total="total"
- :page.sync="pageNo"
- :limit.sync="pageSize"
- @pagination="handleSearch"
- />
- <!-- 弹窗 -->
- <ReportPrint ref="reportPrint" />
- <ParameterDetail ref="parameterDetailRef" @success="getQueryData" />
- </el-card>
- </template>
- <script>
- import * as QueryManageApi from "@/api/mes/queryManage";
- import { getQueryManageButtonPage } from "@/api/mes/queryManage/button";
- import { saveAs } from "file-saver";
- import * as XLSX from "xlsx";
- import FilterColumnInQuery from "./components/FilterColumnInQuery.vue";
- import DictTag from "./components/DictTag.vue";
- import ParameterDetail from "./components/ParameterDetail.vue";
- import ReportPrint from "./components/ReportPrint.vue";
- import request from "@/utils/request";
- import { getAccessToken, getTenantId } from "@/utils/auth";
- import axios from "axios";
- export default {
- name: "QueryForm",
- components: {
- FilterColumnInQuery,
- ParameterDetail,
- ReportPrint,
- DictTag,
- },
- data() {
- return {
- title: "", // ContentWrap 的 title
- message: "", // ContentWrap 的 message
- queryList: [],
- searchData: [],
- queryData: [],
- list: [],
- originalList: [],
- pageNo: 1,
- pageSize: 20,
- total: 0,
- loading: false,
- form: {},
- visible: false,
- customFilters: {},
- currentSortField: null,
- currentSortDirection: null,
- dynamicButtons: [],
- queryParamList: [],
- exportLoading: false,
- showMultipleList: [],
- isClear: false,
- multipleSelection: [],
- headerWidthChange: false,
- };
- },
- mounted() {
- this.init();
- },
- activated() {
- this.init();
- },
- beforeDestroy() {
- this.saveColumnWidth();
- },
- methods: {
- /* 生命周期 */
- async init() {
- this.title =
- this.$route.query?.name ||
- this.$route.redirectedFrom?.meta?.title ||
- "查询";
- // 需要提示文字时,再写 this.message = 'xxx'
- if (this.$route.query.infraQueryId) {
- await this.getFilterData();
- } else {
- this.buildQueryParamFromRoute();
- await this.getQueryData();
- }
- },
- /* 以下所有方法保持与原文件一致,不再赘述 */
- async getQueryData() {
- try {
- this.loading = true;
- const data = await QueryManageApi.getQueryManageColumnListByMasterId(
- this.$route.query.id
- );
- // 确保queryData是数组
- this.queryData = Array.isArray(data.data) ? data.data || [] : [];
- console.log("queryData长度", this.queryData.length);
- this.searchData = this.queryData.filter(
- (item) => item.listOperationResult && item.ifHide === false
- );
- this.showMultipleList = this.queryData.filter(
- (item) => item.listOperationCondition === "1"
- );
- this.queryList = [];
- for (let i = 0; i < this.searchData.length; i++) {
- const { dataType, htmlType, dictType, columnName } =
- this.searchData[i];
- this.queryList.push({
- dataType,
- htmlType,
- dictType,
- key: columnName,
- operate: dataType === "ym_string_query_type" ? "like" : "",
- });
- }
- await this.getManageButtons(this.$route.query?.id);
- await this.getList();
- } finally {
- this.loading = false;
- }
- },
- async getList() {
- console.log("getList被调用,queryParamList:", this.queryParamList);
- try {
- this.loading = true;
- console.log("调用QueryManageApi.loadTableData,参数:", {
- pageNo: this.pageNo,
- pageSize: this.pageSize,
- paramList: this.queryParamList,
- id: this.$route.query?.id,
- });
- const data = await QueryManageApi.loadTableData({
- pageNo: this.pageNo,
- pageSize: this.pageSize,
- paramList: this.queryParamList,
- id: this.$route.query?.id,
- });
- console.log("后端返回", data);
- this.list = data?.data?.list || [];
- console.log("赋值后 list =", this.list);
- console.log("list.length =", this.list.length);
- console.log("list 第一条 =", this.list[0]);
- this.originalList = JSON.parse(JSON.stringify(data?.data?.list || []));
- this.total = data?.data?.total || 0;
- } catch (error) {
- console.error("getList错误:", error);
- } finally {
- this.loading = false;
- }
- },
- async getManageButtons(masterId) {
- const data = await getQueryManageButtonPage({ masterId });
- this.dynamicButtons = data?.data?.list || [];
- },
- async handleDynamicButtonClick(btn = {}) {
- const {
- ifJimu,
- interfaceUrl,
- printSoft,
- operateType,
- paramList = [],
- } = btn;
- if (ifJimu) {
- this.handlePrintByJimu(btn);
- } else if (this.isFullUrl(interfaceUrl) && printSoft) {
- this.handlePrintByOtherSoft(btn);
- } else if (operateType === 2) {
- this.$refs.parameterDetailRef.open(
- "create",
- btn,
- this.$route.query?.id,
- [],
- this.queryData
- );
- } else if (operateType === 3) {
- if (this.multipleSelection.length === 0)
- return this.$message.warning("请先选择行数据!");
- if (this.multipleSelection.length > 1)
- return this.$message.warning("只能选择单条数据修改!");
- this.$refs.parameterDetailRef.open(
- "update",
- btn,
- this.$route.query?.id,
- this.multipleSelection,
- this.queryData
- );
- } else if (operateType === 7) {
- this.$router.push({ path: `${interfaceUrl}` });
- } else {
- this.handleDynamic(btn);
- }
- },
- formatToDateTime(val) {
- const d = val ? new Date(val) : new Date();
- if (isNaN(d.getTime())) return "";
- const pad = (n) => String(n).padStart(2, "0");
- return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(
- d.getDate()
- )} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
- },
- handlePrintByJimu(params) {
- if (this.multipleSelection.length === 0)
- return this.$message.warning("请先选择数据!");
- const baseUrl = process.env.VITE_BASE_URL;
- const token = getAccessToken();
- const tenantId = getTenantId();
- const { paramList = [], interfaceUrl, reportId } = params;
- const fieldValues = this.paramsToConver(paramList);
- const printParams = new URLSearchParams({
- token,
- tenantId,
- ...fieldValues,
- });
- const src = `${baseUrl}${interfaceUrl}${reportId}?${printParams.toString()}`;
- this.$refs.reportPrint.open(
- src,
- this.$route.query?.name ||
- this.$route.redirectedFrom?.meta?.title ||
- "报表打印"
- );
- },
- async handlePrintByOtherSoft(params) {
- if (this.multipleSelection.length === 0)
- return this.$message.warning("请先选择数据!");
- const { interfaceUrl, paramList, restMethod, templet } = params;
- if (!templet) return this.$message.warning("未配置打印模板!");
- const fieldValues = this.paramsToConver(paramList);
- const printParams = { ...fieldValues, fileUrl: templet };
- const config = {
- method: restMethod,
- url: interfaceUrl,
- [restMethod === "get" || restMethod === "delete" ? "params" : "data"]:
- printParams,
- };
- await axios(config);
- this.$message.success("操作成功!");
- this.getList();
- },
- async handleDynamic(params) {
- if (this.multipleSelection.length === 0)
- return this.$message.warning("请先选择数据!");
- const {
- interfaceUrl,
- restMethod = "get",
- paramList = [],
- requestParameter = "0",
- } = params;
- const fieldValues = this.paramsToConver(paramList);
- const config = { method: restMethod, url: interfaceUrl };
- this.handleGetDelete(config, fieldValues, requestParameter);
- await request[restMethod]?.(config);
- this.$message.success("操作成功");
- this.getList();
- },
- handleGetDelete(config, fieldValues, requestParameter) {
- switch (requestParameter) {
- case "1":
- config.params = fieldValues;
- break;
- case "3":
- config.url = new URLSearchParams(fieldValues).toString()
- ? `${config.url}?${new URLSearchParams(fieldValues).toString()}`
- : config.url;
- break;
- case "4":
- config.headers = { ...config.headers, ...fieldValues };
- break;
- default:
- config.data = fieldValues;
- }
- },
- paramsToConver(paramList) {
- const matchListWithParam = paramList
- ?.filter((item) =>
- this.queryData.some((query) => item.columnId === query?.id)
- )
- .map((item) => {
- const paramItem = this.queryData.find(
- (query) => item.columnId === query?.id
- );
- return { ...item, columnComment: paramItem?.columnComment };
- });
- const result = this.generateMappedData(
- this.multipleSelection,
- matchListWithParam
- );
- const allFields = [...new Set(result.flatMap(Object.keys))];
- return allFields.reduce((acc, field) => {
- acc[field] = result.map((item) => item[field]).join(",");
- return acc;
- }, {});
- },
- generateMappedData(selectList, keys) {
- return selectList.map((item) =>
- keys.reduce((res, key) => {
- const { columnComment, paramName } = key;
- if (item.hasOwnProperty(columnComment)) {
- const field = paramName.split(".").pop();
- res[field] = item[columnComment];
- }
- return res;
- }, {})
- );
- },
- isFullUrl(url) {
- try {
- const parsed = new URL(url);
- return parsed.protocol === "http:" || parsed.protocol === "https:";
- } catch {
- return false;
- }
- },
- isDict(key) {
- if (!Array.isArray(this.queryData)) return false;
- const item = this.queryData.find((item) => item.columnComment === key);
- return item ? item.dictType : false;
- },
- isNumber(key) {
- if (!Array.isArray(this.queryData)) return false;
- const item = this.queryData.find((item) => item.columnComment === key);
- return item && item.dataType === "ym_int_query_type";
- },
- isDateTime(key) {
- if (!Array.isArray(this.queryData)) return false;
- const item = this.queryData.find((item) => item.columnComment === key);
- return item && item.javaType === "LocalDateTime";
- },
- hasFilter(field) {
- return !!(this.customFilters[field] && this.customFilters[field].length);
- },
- handleSort(field, direction) {
- if (
- this.currentSortField === field &&
- this.currentSortDirection === direction
- ) {
- this.currentSortField = "";
- this.currentSortDirection = "";
- this.list = JSON.parse(JSON.stringify(this.originalList));
- return;
- }
- this.currentSortField = field;
- this.currentSortDirection = direction;
- this.list = [...this.originalList].sort((a, b) => {
- let valA = a[field];
- let valB = b[field];
- valA =
- typeof valA === "string" ? parseFloat(valA.replace(/,/g, "")) : valA;
- valB =
- typeof valB === "string" ? parseFloat(valB.replace(/,/g, "")) : valB;
- if (isNaN(valA))
- return direction === "asc"
- ? valA > valB
- ? 1
- : -1
- : valA < valB
- ? 1
- : -1;
- if (isNaN(valB))
- return direction === "asc"
- ? valA > valB
- ? 1
- : -1
- : valA < valB
- ? 1
- : -1;
- return direction === "asc" ? valA - valB : valB - valA;
- });
- },
- filterData(data, field, type, row) {
- console.log("filterData被调用:", { data, field, type, row });
- const { dataType } = row;
- this.$set(this.customFilters, field, data);
- const isDateRange = data[0]?.isRange;
- if (isDateRange) {
- const valueList = data.flatMap((item) => item.column).join(",");
- const idx = this.queryParamList.findIndex((item) => item.key === field);
- if (idx > -1) {
- this.queryParamList[idx].value = valueList;
- } else {
- this.queryParamList.push({
- key: field,
- operate: "like",
- htmlType: type,
- value: valueList,
- });
- }
- console.log(
- "filterData - 日期范围筛选后queryParamList:",
- this.queryParamList
- );
- this.getList();
- return;
- }
- let valueStr;
- if (data.length) {
- valueStr =
- dataType === "ym_int_query_type"
- ? data.map((item) => item.column).join(",")
- : data.map((item) => `'${item.column}'`).join(",");
- const idx = this.queryParamList.findIndex((item) => item.key === field);
- if (idx > -1) {
- this.queryParamList[idx].value = valueStr;
- } else {
- this.queryParamList.push({
- key: field,
- operate: "like",
- htmlType: type,
- value: valueStr,
- });
- }
- } else {
- const idx = this.queryParamList.findIndex((item) => item.key === field);
- if (idx > -1) this.queryParamList.splice(idx, 1);
- }
- console.log("filterData - 筛选后queryParamList:", this.queryParamList);
- this.getList();
- },
- AllConditionReset() {
- this.queryParamList = [];
- this.customFilters = {};
- this.isClear = true;
- setTimeout(() => (this.isClear = false), 1000);
- this.getList();
- },
- handleSearch() {
- this.list = [];
- this.getList();
- },
- async Export() {
- try {
- await this.$confirm("确定导出当前页?", "提示", { type: "warning" });
- setTimeout(() => {
- const xlsxParam = { raw: true };
- const tables = document.getElementById("table_excel");
- const table_book = XLSX.utils.table_to_book(tables, xlsxParam);
- const tableWrite = XLSX.write(table_book, {
- bookType: "xlsx",
- bookSST: true,
- type: "array",
- });
- saveAs(
- new Blob([tableWrite], { type: "application/octet-stream" }),
- `${this.title}.xlsx`
- );
- }, 1000);
- } catch {}
- },
- async ExportAll() {
- try {
- await this.$confirm("确定导出全部?", "提示", { type: "warning" });
- this.exportLoading = true;
- const data = await QueryManageApi.exportExcel({
- id: this.$route.query?.id,
- paramList: this.queryParamList,
- });
- this.$download.excel(data, this.title + ".xls");
- } finally {
- this.exportLoading = false;
- }
- },
- getHandleNumber(val) {
- return Math.round(parseFloat(val) * 100000000) / 100000000;
- },
- getSummaries({ columns }) {
- const sums = [];
- columns.forEach((column, index) => {
- if (index === 0) {
- sums[index] = "总计";
- return;
- }
- const values = this.list.map((item) => Number(item[column.property]));
- if (this.isNumber(column.property)) {
- sums[index] = values.reduce((acc, cur) => {
- const value = Number(cur);
- return !isNaN(value) ? this.getHandleNumber(acc + cur) : acc;
- }, 0);
- }
- });
- return sums;
- },
- handleSelectionChange(val) {
- this.multipleSelection = val;
- },
- pathChange(path, val, item, row) {
- if (path === "sameRouter") return;
- if (!path) return;
- const data = {};
- this.dynamicButtons
- .filter((v) => v.ifHide && v.paramList.length)
- .forEach((v) =>
- v.paramList.forEach((val) => {
- data[val.paramName] = val.value || row[val.paramComment];
- })
- );
- this.$router.push({ path: `${path}`, query: { id: val, ...data } });
- },
- handleBack() {
- this.$router.push({ path: "/querymanage/queryManageIndex" });
- },
- handleResize() {
- this.headerWidthChange = true;
- },
- async saveColumnWidth() {
- if (!this.headerWidthChange) return;
- this.headerWidthChange = false;
- const widthList = [];
- // 确保queryData是数组
- if (!Array.isArray(this.queryData)) return;
- const headers = this.$refs.tableRef.$el.querySelectorAll(
- ".el-table__header-wrapper tr th"
- );
- const visibleColumns = this.queryData.filter((item) => !item.ifHide);
- const validHeaders = [...headers].filter(
- (th) =>
- !th.classList.contains("el-table-column--selection") &&
- th.innerText.trim() !== ""
- );
- validHeaders.forEach((header, i) => {
- const correspondingItem = visibleColumns[i];
- if (correspondingItem) {
- widthList.push({
- id: correspondingItem.id,
- javaField: header.offsetWidth,
- });
- }
- });
- await QueryManageApi.updateWidth(widthList);
- },
- buildQueryParamFromRoute() {
- const queryParam = [];
- for (const i in this.$route.query) {
- if (i !== "id" && i !== "name") {
- queryParam.push({
- key: i,
- operate: "like",
- htmlType: "input",
- value: "'" + this.$route.query[i] + "'",
- });
- }
- }
- this.queryParamList = queryParam;
- },
- async getFilterData() {
- const data = await getQueryManageButtonPage({
- masterId: this.$route.query?.infraQueryId,
- });
- const arr = [];
- data.list
- .filter((v) => v.ifHide && v.paramList.length)
- .forEach((v) =>
- v.paramList.forEach((val) => {
- if (val.filter) arr.push(val.paramName);
- })
- );
- const queryParam = [];
- for (const i in this.$route.query) {
- if (arr.indexOf(i) > -1) {
- queryParam.push({
- key: i,
- operate: "like",
- htmlType: "input",
- value: "'" + this.$route.query[i] + "'",
- });
- }
- }
- this.queryParamList = queryParam;
- await this.getQueryData();
- },
- },
- };
- </script>
- <style scoped lang="scss">
- /* ---------- ContentWrap 原样式 ---------- */
- .el-content-wrap {
- /* 自定义 */
- }
- .text-16px {
- font-size: 16px;
- }
- .font-700 {
- font-weight: 700;
- }
- .ml-5px {
- margin-left: 5px;
- }
- .max-w-200px {
- max-width: 200px;
- }
- .mb-3px {
- margin-bottom: 3px;
- }
- /* ---------- 原来的表格样式 ---------- */
- :deep(.el-table__row) {
- height: 15px !important;
- }
- .el-table--medium .el-table__cell,
- .el-table--small .el-table__cell {
- padding: 1px 0 !important;
- }
- .active:hover {
- cursor: pointer;
- }
- .has-filter,
- .is-sort,
- .active {
- color: #1890ff !important;
- }
- </style>
|