20260711173006
This commit is contained in:
1 parent
d080a2a48d
commit
446758b2fe
384 files changed
+153926
-5937
No files matched your search
Whitespace-only changes.
@@ -0,0 +1,43 @@
|
||||
import { ElMessage } from "element-plus";
|
||||
import { ref } from "vue";
|
||||
import { useUserStore } from "@/store/user";
|
||||
import axios from "@/utils/axios";
|
||||
|
||||
const saving = ref(false);
|
||||
const error = ref(null);
|
||||
|
||||
export function morePermission(permissionId) {
|
||||
const userStore = useUserStore();
|
||||
return !userStore.hasActionPermission(permissionId);
|
||||
}
|
||||
|
||||
export async function getQxSql(moduleId, userId) {
|
||||
saving.value = true;
|
||||
error.value = "";
|
||||
|
||||
try {
|
||||
const response = await axios.get("/getQxSql", {
|
||||
params: {
|
||||
moduleId, // 必填
|
||||
userId, // 可选
|
||||
},
|
||||
});
|
||||
if (response.data?.success) {
|
||||
return response.data.data;
|
||||
} else {
|
||||
throw new Error(response.data?.message || "生成id失败");
|
||||
}
|
||||
} catch (err) {
|
||||
error.value = `生成id: ${err.message}`;
|
||||
ElMessage.error(error.value);
|
||||
return null;
|
||||
} finally {
|
||||
saving.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 默认导出所有方法
|
||||
export default {
|
||||
morePermission,
|
||||
getQxSql,
|
||||
};
|
||||
@@ -0,0 +1,33 @@
|
||||
// src/utils/axios.js
|
||||
import axios from "axios";
|
||||
import { useUserStore } from "@/store";
|
||||
|
||||
const instance = axios.create({
|
||||
// baseURL: "http://localhost:8089/api", // 后端接口地址
|
||||
baseURL: 'http://192.168.1.137:8089/api', // 后端接口地址
|
||||
// baseURL: "http://192.168.1.137:8089/api",
|
||||
// baseURL: '/api', // 后端接口地址
|
||||
timeout: 30000,
|
||||
});
|
||||
|
||||
// 请求拦截器:自动添加 token
|
||||
instance.interceptors.request.use(
|
||||
(config) => {
|
||||
const userStore = useUserStore();
|
||||
if (userStore.isLogined()) {
|
||||
config.headers.Authorization = `Bearer ${userStore.userInfo.token}`;
|
||||
}
|
||||
return config;
|
||||
},
|
||||
(error) => Promise.reject(error),
|
||||
);
|
||||
|
||||
// 响应拦截器:统一处理错误或过期 token
|
||||
instance.interceptors.response.use(
|
||||
(response) => response,
|
||||
(error) => {
|
||||
return Promise.reject(error);
|
||||
},
|
||||
);
|
||||
|
||||
export default instance;
|
||||
@@ -0,0 +1,141 @@
|
||||
import Big from "big.js";
|
||||
import { formatToDate } from "./time";
|
||||
|
||||
/**
|
||||
* 根据 format 判断列对齐方式
|
||||
* @param {string} format
|
||||
*/
|
||||
export function getAlignByFormat(format) {
|
||||
if (!format || typeof format !== "string") return "left";
|
||||
|
||||
const fmt = format.trim().toLowerCase();
|
||||
if (fmt.startsWith("money") || fmt.startsWith("number")) {
|
||||
return "right";
|
||||
}
|
||||
|
||||
if (fmt === "checkbox") {
|
||||
return "center";
|
||||
}
|
||||
|
||||
return "left";
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 format 格式化值
|
||||
* @param {any} value 原始值
|
||||
* @param {string} format 格式描述,如 money(2)、percent(1)
|
||||
*/
|
||||
export function formatValueByFormat(value, format) {
|
||||
if (value === null || value === undefined || value === "") return "";
|
||||
|
||||
if (!format || typeof format !== "string") return value;
|
||||
|
||||
const fmt = format.trim().toLowerCase();
|
||||
|
||||
// money(n)
|
||||
if (fmt.startsWith("money")) {
|
||||
const match = fmt.match(/^money\((\d+)\)$/);
|
||||
const decimals = match ? Number(match[1]) : 2;
|
||||
|
||||
const num = Number.parseFloat(value);
|
||||
if (Number.isNaN(num)) return value;
|
||||
|
||||
// 使用Intl.NumberFormat来处理千分位
|
||||
return new Intl.NumberFormat("en-US", {
|
||||
minimumFractionDigits: decimals,
|
||||
maximumFractionDigits: decimals,
|
||||
}).format(num);
|
||||
} else if (fmt.startsWith("date")) {
|
||||
return formatToDate(value);
|
||||
} else if (fmt.startsWith("number")) {
|
||||
return Number(value) || 0;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 format 格式化值
|
||||
* @param {any} value 原始值
|
||||
* @param {string} format 格式描述,如 money(2)、percent(1)
|
||||
*/
|
||||
export function formatValueByFullFormat(value, format) {
|
||||
if (value === null || value === undefined || value === "") return "";
|
||||
|
||||
if (!format || typeof format !== "string") return value;
|
||||
|
||||
const fmt = format.trim().toLowerCase();
|
||||
|
||||
// money(n)
|
||||
if (fmt.startsWith("money")) {
|
||||
const match = fmt.match(/^money\((\d+)\)$/);
|
||||
const decimals = match ? Number(match[1]) : 2;
|
||||
|
||||
const num = Number.parseFloat(value);
|
||||
if (Number.isNaN(num)) return value;
|
||||
|
||||
return num.toFixed(decimals);
|
||||
} else if (fmt.startsWith("date")) {
|
||||
return formatToDate(value);
|
||||
} else if (fmt.startsWith("number")) {
|
||||
return Number(value) || 0;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
export function updateTableFooterData(columns, tableData, includeSeq = true) {
|
||||
// 初始化合计数据
|
||||
const footerData = columns.reduce((acc, col) => {
|
||||
// 如果当前列有子列,递归处理子列的合计
|
||||
if (col.children && col.children.length > 0) {
|
||||
// 递归计算子列的合计数据
|
||||
const childFooterData = updateTableFooterData(col.children, tableData, false);
|
||||
|
||||
// 将子列的合计合并到父列中
|
||||
childFooterData.forEach((childData) => {
|
||||
for (const [key, value] of Object.entries(childData)) {
|
||||
if (!acc[key]) {
|
||||
acc[key] = new Big(0);
|
||||
}
|
||||
acc[key] = acc[key].plus(new Big(value));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// 只有showSummary为'1'的列才参与合计
|
||||
if (col.showSummary === "1") {
|
||||
// 计算当前列的合计
|
||||
const total = tableData.reduce((sum, row) => {
|
||||
let value = row[col.prop] || 0;
|
||||
|
||||
// 使用 Big 来避免浮动点问题
|
||||
return sum.plus(new Big(value));
|
||||
}, new Big(0));
|
||||
|
||||
// 将未格式化的合计结果存入acc
|
||||
acc[col.prop] = total;
|
||||
}
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
for (const [key, value] of Object.entries(footerData)) {
|
||||
const column = columns.find((col) => col.prop === key); // 找到对应的列信息
|
||||
if (column) {
|
||||
footerData[key] = formatValueByFullFormat(value, column.displayFormat);
|
||||
}
|
||||
}
|
||||
|
||||
// 返回合计结果
|
||||
if (includeSeq) {
|
||||
return [
|
||||
{
|
||||
seq: "合计",
|
||||
...footerData,
|
||||
},
|
||||
];
|
||||
} else {
|
||||
return [footerData];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import { ElMessage } from "element-plus";
|
||||
import { ref } from "vue";
|
||||
import axios from "@/utils/axios";
|
||||
|
||||
const saving = ref(false);
|
||||
const error = ref(null);
|
||||
|
||||
export async function getSFId() {
|
||||
saving.value = true;
|
||||
error.value = "";
|
||||
|
||||
try {
|
||||
const response = await axios.get("/getSFId");
|
||||
if (response.data?.success) {
|
||||
return String(response.data.data);
|
||||
} else {
|
||||
throw new Error(response.data?.message || "生成id失败");
|
||||
}
|
||||
} catch (err) {
|
||||
error.value = `生成id: ${err.message}`;
|
||||
ElMessage.error(error.value);
|
||||
return null;
|
||||
} finally {
|
||||
saving.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getAutoId(moduleId, userId) {
|
||||
saving.value = true;
|
||||
error.value = "";
|
||||
|
||||
try {
|
||||
const response = await axios.get("/getAutoId", {
|
||||
params: {
|
||||
moduleId, // 必填
|
||||
userId, // 可选
|
||||
},
|
||||
});
|
||||
if (response.data?.success) {
|
||||
return response.data.data;
|
||||
} else {
|
||||
throw new Error(response.data?.message || "查询失败");
|
||||
}
|
||||
} catch (err) {
|
||||
error.value = `查询失败: ${err.message}`;
|
||||
ElMessage.error(error.value);
|
||||
return null;
|
||||
} finally {
|
||||
saving.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 默认导出所有方法
|
||||
export default {
|
||||
getSFId,
|
||||
getAutoId,
|
||||
};
|
||||
@@ -0,0 +1,471 @@
|
||||
/* 比对并分类数据变更
|
||||
* @param {Array} currentData 变更后的数据数组
|
||||
* @param {Array} originalData 原始数据数组
|
||||
* @param {String} primaryKey 主键字段名
|
||||
* @param {Array} ignoreFields 过滤字段(可传可不传)
|
||||
* @returns {Object} 包含分类结果的对象 { insertdata: [], updatedata: [], deletedata: [], hasChanges: Boolean }
|
||||
*/
|
||||
export function compareAndClassifyData(currentData, originalData, primaryKey) {
|
||||
const versionFields = ["mx_version", "b_version"];
|
||||
const getVersionFields = (row) => {
|
||||
const fields = {};
|
||||
versionFields.forEach((key) => {
|
||||
if (Object.prototype.hasOwnProperty.call(row, key)) {
|
||||
fields[key] = row[key] ?? "";
|
||||
}
|
||||
});
|
||||
return fields;
|
||||
};
|
||||
|
||||
const result = {
|
||||
inserts: [],
|
||||
updates: [],
|
||||
deletes: [],
|
||||
hasChanges: false, // 默认无变动
|
||||
};
|
||||
|
||||
// 1. 找出新增的数据
|
||||
result.inserts = currentData.filter(
|
||||
(row) =>
|
||||
!row[primaryKey] ||
|
||||
!originalData.some((originalRow) => originalRow[primaryKey] === row[primaryKey]),
|
||||
);
|
||||
|
||||
// 2. 找出修改的数据
|
||||
result.updates = currentData.reduce((acc, row) => {
|
||||
const rowId = row[primaryKey];
|
||||
if (!rowId) return acc;
|
||||
|
||||
const originalRow = originalData.find((r) => r[primaryKey] === rowId);
|
||||
if (!originalRow) return acc;
|
||||
|
||||
const changedFields = {};
|
||||
Object.keys(row).forEach((key) => {
|
||||
if (key !== primaryKey && !key.startsWith("v_") && !versionFields.includes(key)) {
|
||||
const oldVal = originalRow[key];
|
||||
const newVal = row[key];
|
||||
|
||||
const normalize = (v) => (v === null || v === undefined ? "" : v);
|
||||
|
||||
if (normalize(newVal) !== normalize(oldVal)) {
|
||||
// ✅ 避免 undefined 被丢弃
|
||||
changedFields[key] = newVal ?? "";
|
||||
}
|
||||
}
|
||||
});
|
||||
// Object.keys(row).forEach((key) => {
|
||||
// if (key !== primaryKey && !isEqual(row[key], originalRow[key])) {
|
||||
// if (!key.startsWith('v_')) {
|
||||
// changedFields[key] = row[key]
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
|
||||
if (Object.keys(changedFields).length > 0) {
|
||||
acc.push({
|
||||
[primaryKey]: rowId,
|
||||
...getVersionFields(row),
|
||||
...changedFields,
|
||||
});
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
// 3. 找出删除的数据
|
||||
result.deletes = originalData.filter(
|
||||
(originalRow) => !currentData.some((row) => row[primaryKey] === originalRow[primaryKey]),
|
||||
);
|
||||
|
||||
// 4. 是否有任何变动
|
||||
result.hasChanges =
|
||||
result.inserts.length > 0 || result.updates.length > 0 || result.deletes.length > 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 在数组对象的每个元素中覆盖式填入 JSON 对象的值
|
||||
* @param {Array} arr - 目标数组(将被修改)
|
||||
* @param {object} json - 包含要添加/覆盖的键值对的 JSON 对象
|
||||
* @returns {Array} 修改后的数组
|
||||
* @throws {Error} 当参数类型不正确时抛出错误
|
||||
*/
|
||||
// export function fillDefaultArray(arr, json) {
|
||||
// // 基本数据验证
|
||||
// if (!Array.isArray(arr))
|
||||
// throw new Error('第一个参数必须是数组')
|
||||
// if (typeof json !== 'object' || json === null || Array.isArray(json)) {
|
||||
// throw new Error('第二个参数必须是普通对象(JSON对象)')
|
||||
// }
|
||||
|
||||
// // 覆盖式填充每个元素
|
||||
// return arr.map((item) => {
|
||||
// // 只处理对象元素
|
||||
// if (typeof item === 'object' && item !== null) {
|
||||
// return { ...item, ...json } // 覆盖已有属性
|
||||
// }
|
||||
// return item // 非对象元素保持不变
|
||||
// })
|
||||
// }
|
||||
|
||||
export function fillDefaultArray(arr, json) {
|
||||
// 基本数据验证
|
||||
if (!Array.isArray(arr)) throw new Error("第一个参数必须是数组");
|
||||
|
||||
if (typeof json !== "object" || json === null || Array.isArray(json)) {
|
||||
throw new Error("第二个参数必须是普通对象(JSON对象)");
|
||||
}
|
||||
|
||||
// 原地修改数组中的每个对象
|
||||
for (const item of arr) {
|
||||
if (typeof item === "object" && item !== null) {
|
||||
Object.assign(item, json);
|
||||
}
|
||||
}
|
||||
|
||||
// 可选:方便链式调用
|
||||
return arr;
|
||||
}
|
||||
|
||||
// export function fillSerialNoAndDefaults(arr, defaults = {}) {
|
||||
// if (!Array.isArray(arr)) return;
|
||||
|
||||
// arr.forEach((item, index) => {
|
||||
// if (typeof item === "object" && item !== null) {
|
||||
// item.mx_xh = index + 1;
|
||||
// Object.assign(item, defaults);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
export function fillSerialNoAndDefaults(arr, defaults = {}) {
|
||||
if (!Array.isArray(arr)) return;
|
||||
|
||||
arr.forEach((item, index) => {
|
||||
if (typeof item === "object" && item !== null) {
|
||||
item.mx_xh = index + 1;
|
||||
|
||||
Object.entries(defaults).forEach(([key, value]) => {
|
||||
item[key] = typeof value === "function" ? value(item, index) : value;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function compareAndClassifyData1(currentData, originalData, primaryKey, ignoreFields = []) {
|
||||
const ignoreSet = new Set(ignoreFields);
|
||||
|
||||
const result = {
|
||||
insertdata: [],
|
||||
updatedata: [],
|
||||
deletedata: [],
|
||||
hasChanges: false,
|
||||
};
|
||||
|
||||
// 工具函数:剔除不需要的字段
|
||||
const omitFields = (row) => {
|
||||
const res = {};
|
||||
Object.keys(row).forEach((key) => {
|
||||
if (key !== primaryKey && ignoreSet.has(key)) return;
|
||||
res[key] = row[key];
|
||||
});
|
||||
return res;
|
||||
};
|
||||
|
||||
// 1️⃣ 新增
|
||||
result.insertdata = currentData
|
||||
.filter(
|
||||
(row) => !row[primaryKey] || !originalData.some((o) => o[primaryKey] === row[primaryKey]),
|
||||
)
|
||||
.map((row) => omitFields(row)); // 在插入时过滤字段
|
||||
|
||||
// 2️⃣ 修改
|
||||
result.updatedata = currentData.reduce((acc, row) => {
|
||||
const rowId = row[primaryKey];
|
||||
if (!rowId) return acc;
|
||||
|
||||
const originalRow = originalData.find((r) => r[primaryKey] === rowId);
|
||||
if (!originalRow) return acc;
|
||||
|
||||
const changedFields = {};
|
||||
Object.keys(row).forEach((key) => {
|
||||
if (key === primaryKey || ignoreSet.has(key)) return; // 忽略指定字段
|
||||
|
||||
if (row[key] !== originalRow[key]) changedFields[key] = row[key];
|
||||
});
|
||||
|
||||
if (Object.keys(changedFields).length > 0) {
|
||||
acc.push({
|
||||
[primaryKey]: rowId,
|
||||
...omitFields(changedFields), // 在更新时也过滤字段
|
||||
});
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
// 3️⃣ 删除,只保留 primaryKey
|
||||
result.deletedata = originalData
|
||||
.filter((o) => !currentData.some((c) => c[primaryKey] === o[primaryKey]))
|
||||
.map((row) => ({ [primaryKey]: row[primaryKey] }));
|
||||
|
||||
// 4️⃣ 是否有变动
|
||||
result.hasChanges =
|
||||
result.insertdata.length > 0 || result.updatedata.length > 0 || result.deletedata.length > 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 深度比较两个值是否相等
|
||||
* @param {*} a 第一个值
|
||||
* @param {*} b 第二个值
|
||||
* @returns {boolean} 是否相等
|
||||
*/
|
||||
export function isEqual(a, b) {
|
||||
// 处理基本类型和null/undefined
|
||||
if (a === b) return true;
|
||||
if (typeof a !== typeof b) return false;
|
||||
if (typeof a !== "object" || a === null || b === null) {
|
||||
return a === b;
|
||||
}
|
||||
|
||||
// 处理数组
|
||||
if (Array.isArray(a) && Array.isArray(b)) {
|
||||
if (a.length !== b.length) return false;
|
||||
return a.every((item, i) => isEqual(item, b[i]));
|
||||
}
|
||||
|
||||
// 处理对象
|
||||
const keysA = Object.keys(a);
|
||||
const keysB = Object.keys(b);
|
||||
|
||||
if (keysA.length !== keysB.length) return false;
|
||||
|
||||
return keysA.every((key) => isEqual(a[key], b[key]));
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测并提取变更的字段(跳过v_开头的字段)
|
||||
* @param {object} currentData 当前数据
|
||||
* @param {object} originalData 原始数据
|
||||
* @param {string} primaryKey 主键字段名
|
||||
* @param {string} primaryKeyValue 主键值
|
||||
* @returns {object} 包含变更数据的对象,结构为 { hasChanges: boolean, updateData: Object }
|
||||
*/
|
||||
export function detectChanges(currentData, originalData, primaryKey, primaryKeyValue) {
|
||||
const updateValue = {};
|
||||
|
||||
// 遍历所有字段检测变更
|
||||
Object.keys(currentData).forEach((key) => {
|
||||
// 跳过以v_开头的字段
|
||||
if (key.startsWith("v_")) return;
|
||||
|
||||
if (key === "b_type") {
|
||||
const currentStr = normalizeOwnerCustomer(currentData[key]);
|
||||
const originalStr = normalizeOwnerCustomer(originalData[key]);
|
||||
|
||||
if (currentStr !== originalStr) {
|
||||
updateValue[key] = currentStr; // 保存时格式化为逗号分隔字符串
|
||||
}
|
||||
} else {
|
||||
// 比较前,先将 undefined 转换为空字符串
|
||||
const currentValue = currentData[key] === undefined ? "" : currentData[key];
|
||||
const originalValue = originalData[key] === undefined ? "" : originalData[key];
|
||||
|
||||
// 使用JSON.stringify进行深度比较
|
||||
if (JSON.stringify(currentValue) !== JSON.stringify(originalValue)) {
|
||||
updateValue[key] = currentValue;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 如果没有有效变更
|
||||
if (Object.keys(updateValue).length === 0) {
|
||||
return { hasChanges: true, updateData: [] };
|
||||
}
|
||||
|
||||
// 返回变更数据和主键
|
||||
return {
|
||||
hasChanges: true,
|
||||
updateData: [
|
||||
{
|
||||
[primaryKey]: primaryKeyValue,
|
||||
...updateValue,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测并提取变更的字段(跳过v_开头的字段和指定排除字段)
|
||||
* @param {object} currentData 当前数据
|
||||
* @param {object} originalData 原始数据
|
||||
* @param {Array|string} primaryKeys 主键字段名或数组
|
||||
* @param {Array} excludeKeys 可选,排除的字段数组
|
||||
* @returns {object} 包含变更数据的对象,结构为 { hasChanges: boolean, updateData: Array }
|
||||
*/
|
||||
export function detectChangesFields(currentData, originalData, primaryKeys, excludeKeys = []) {
|
||||
const updateValue = {};
|
||||
|
||||
Object.keys(currentData).forEach((key) => {
|
||||
// 跳过以v_开头的字段
|
||||
if (key.startsWith("v_")) return;
|
||||
|
||||
// 跳过排除字段
|
||||
if (excludeKeys.includes(key)) return;
|
||||
|
||||
const currentValue = currentData[key] === undefined ? "" : currentData[key];
|
||||
const originalValue = originalData[key] === undefined ? "" : originalData[key];
|
||||
|
||||
if (JSON.stringify(currentValue) !== JSON.stringify(originalValue)) {
|
||||
updateValue[key] = currentValue;
|
||||
}
|
||||
});
|
||||
|
||||
if (Object.keys(updateValue).length === 0) {
|
||||
return { hasChanges: false, updateData: [] };
|
||||
}
|
||||
|
||||
// 构建主键字段对象
|
||||
const primaryKeyObj = {};
|
||||
if (Array.isArray(primaryKeys)) {
|
||||
primaryKeys.forEach((key) => {
|
||||
primaryKeyObj[key] = originalData[key];
|
||||
});
|
||||
} else {
|
||||
primaryKeyObj[primaryKeys] = originalData[primaryKeys];
|
||||
}
|
||||
|
||||
return {
|
||||
hasChanges: true,
|
||||
updateData: [
|
||||
{
|
||||
...primaryKeyObj,
|
||||
...updateValue,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeOwnerCustomer(val) {
|
||||
if (typeof val === "string") {
|
||||
return val.split(",").filter(Boolean).join(","); // '001,002,003'
|
||||
}
|
||||
|
||||
if (Array.isArray(val)) {
|
||||
return val.map((item) => (Array.isArray(item) ? item[0] : item)).join(",");
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一数据差异比对(主表 / 子表通用)
|
||||
*
|
||||
* @param {Array | object} current 当前数据
|
||||
* @param {Array | object} original 原始数据
|
||||
* @param {string | Array} primaryKey 主键
|
||||
* @param {object} options
|
||||
* @param {Array} options.ignoreFields 忽略字段(如 v_ 字段)
|
||||
* @param {boolean} options.isSingle 是否单条主表
|
||||
*/
|
||||
export function diffData(
|
||||
current,
|
||||
original,
|
||||
primaryKey,
|
||||
{ ignoreFields = [], isSingle = false } = {},
|
||||
) {
|
||||
const ignoreSet = new Set(ignoreFields);
|
||||
|
||||
const result = {
|
||||
hasChanges: false,
|
||||
insertdata: [],
|
||||
updatedata: [],
|
||||
deletedata: [],
|
||||
};
|
||||
|
||||
// ===========================
|
||||
// 单表处理
|
||||
// ===========================
|
||||
if (isSingle) {
|
||||
const isNewRecord = !original || Object.keys(original).length === 0 || !original[primaryKey];
|
||||
|
||||
// 新增
|
||||
if (isNewRecord) {
|
||||
result.hasChanges = true;
|
||||
result.insertdata.push(JSON.parse(JSON.stringify(current)));
|
||||
return result;
|
||||
}
|
||||
|
||||
// 修改
|
||||
const changes = {};
|
||||
Object.keys(current).forEach((key) => {
|
||||
if (key.startsWith("v_") || ignoreSet.has(key)) return;
|
||||
const cur = current[key] ?? "";
|
||||
const org = original[key] ?? "";
|
||||
if (JSON.stringify(cur) !== JSON.stringify(org)) {
|
||||
changes[key] = cur;
|
||||
}
|
||||
});
|
||||
|
||||
if (Object.keys(changes).length > 0) {
|
||||
result.hasChanges = true;
|
||||
result.updatedata.push({ [primaryKey]: current[primaryKey], ...changes });
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// ===========================
|
||||
// 子表处理(优化 Map 提升性能)
|
||||
// ===========================
|
||||
const pk = Array.isArray(primaryKey) ? primaryKey[0] : primaryKey;
|
||||
const originalMap = new Map(original.map((item) => [item[pk], item]));
|
||||
|
||||
// 新增
|
||||
result.insertdata = current.filter((row) => !row[pk] || !originalMap.has(row[pk]));
|
||||
|
||||
// 修改
|
||||
result.updatedata = [];
|
||||
current.forEach((row) => {
|
||||
const id = row[pk];
|
||||
if (!id) return;
|
||||
const oldRow = originalMap.get(id);
|
||||
if (!oldRow) return;
|
||||
|
||||
const changes = {};
|
||||
Object.keys(row).forEach((key) => {
|
||||
if (key === pk || key.startsWith("v_") || ignoreSet.has(key)) return;
|
||||
const cur = row[key] ?? "";
|
||||
const org = oldRow[key] ?? "";
|
||||
if (JSON.stringify(cur) !== JSON.stringify(org)) {
|
||||
changes[key] = cur;
|
||||
}
|
||||
});
|
||||
|
||||
if (Object.keys(changes).length > 0) {
|
||||
result.updatedata.push({ [pk]: id, ...changes });
|
||||
}
|
||||
});
|
||||
|
||||
// 删除
|
||||
result.deletedata = original
|
||||
.filter((o) => !current.some((c) => c[pk] === o[pk]))
|
||||
.map((o) => ({ [pk]: o[pk] }));
|
||||
|
||||
result.hasChanges =
|
||||
result.insertdata.length > 0 || result.updatedata.length > 0 || result.deletedata.length > 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 默认导出所有方法
|
||||
export default {
|
||||
isEqual,
|
||||
compareAndClassifyData,
|
||||
detectChanges,
|
||||
fillDefaultArray,
|
||||
diffData,
|
||||
fillSerialNoAndDefaults,
|
||||
};
|
||||
@@ -0,0 +1,59 @@
|
||||
import { ref } from "vue";
|
||||
import axios from "@/utils/axios";
|
||||
import { ElMessageBox } from "element-plus";
|
||||
|
||||
const saving = ref(false);
|
||||
const error = ref(null);
|
||||
|
||||
export async function delBefore(moduleId, id) {
|
||||
try {
|
||||
saving.value = true;
|
||||
error.value = "";
|
||||
|
||||
const response = await axios.post(
|
||||
"/delBefore",
|
||||
{ moduleId, id },
|
||||
{
|
||||
headers: { "Content-Type": "application/json" },
|
||||
},
|
||||
);
|
||||
//console.log('response=-=-=-=-=-')
|
||||
//console.log(response)
|
||||
return response.data;
|
||||
} catch (err) {
|
||||
error.value = `${err.message}`;
|
||||
return { success: false, message: err.message };
|
||||
} finally {
|
||||
saving.value = false;
|
||||
}
|
||||
}
|
||||
export async function confirmDelete(rows) {
|
||||
const count = rows.length;
|
||||
|
||||
let msg = "确定要删除吗?";
|
||||
if (count == 1) {
|
||||
let id = rows[0].b_id || rows[0].subid || "";
|
||||
msg = "确定要删除 " + id + " 吗?";
|
||||
}
|
||||
|
||||
try {
|
||||
await ElMessageBox.confirm(count > 1 ? `确定要删除选中的 ${count} 条数据吗?` : msg, "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning",
|
||||
});
|
||||
return true;
|
||||
} catch (e) {
|
||||
if (e === "cancel" || e === "close") {
|
||||
return false;
|
||||
}
|
||||
throw e; // 真异常继续抛
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
delBefore,
|
||||
confirmDelete,
|
||||
};
|
||||
|
||||
// 导出单例
|
||||
@@ -0,0 +1,129 @@
|
||||
import axios from "@/utils/axios";
|
||||
|
||||
export async function getDataBySql(sql) {
|
||||
try {
|
||||
const response = await axios.get("/selectlistbysql", {
|
||||
params: { sql }, // GET 请求参数
|
||||
});
|
||||
if (response.data?.success) {
|
||||
return response.data.data;
|
||||
} else {
|
||||
console.error("查询失败:", response.data?.message);
|
||||
return [];
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("接口异常:", err);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export async function getDataBySqlPage(sql, pkColumn, page, size) {
|
||||
try {
|
||||
const response = await axios.get("/selectlistbysqlpage", {
|
||||
params: {
|
||||
sql,
|
||||
pkColumn,
|
||||
page,
|
||||
size,
|
||||
},
|
||||
});
|
||||
if (response.data?.success) {
|
||||
return response.data.data;
|
||||
} else {
|
||||
console.error("查询失败:", response.data?.message);
|
||||
return [];
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("接口异常:", err);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
// const result = await getDataBySqlPageMapping(buildSql(), props.moduleId, props.userId, selectOrder.value, pagination.currentPage, pagination.pageSize)
|
||||
export async function getDataBySqlPageMapping(sql, moduleId, userId, orderby, page, size) {
|
||||
try {
|
||||
const response = await axios.post("/selectlistbysqlpagemapping", {
|
||||
sql,
|
||||
moduleId,
|
||||
userId,
|
||||
orderby,
|
||||
page,
|
||||
size,
|
||||
});
|
||||
if (response.data?.success) {
|
||||
return response.data.data;
|
||||
} else {
|
||||
console.error("查询失败:", response.data?.message);
|
||||
return [];
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("接口异常:", err);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export async function getMultipleDataBySql(sql, return_value, return_value2) {
|
||||
try {
|
||||
const response = await axios.get("/multipleSelectlistbysql", {
|
||||
params: { sql, return_value, return_value2 }, // GET 请求参数
|
||||
});
|
||||
if (response.data?.success) {
|
||||
return response.data.data;
|
||||
} else {
|
||||
console.error("查询失败:", response.data?.message);
|
||||
return [];
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("接口异常:", err);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export async function loaddataApi(viewname, searchcondition) {
|
||||
const { data } = await axios.get("/pagdetail", {
|
||||
params: {
|
||||
tableName: viewname,
|
||||
whereClause: searchcondition,
|
||||
},
|
||||
});
|
||||
|
||||
if (!data?.success) {
|
||||
throw new Error(data?.message || "查询失败");
|
||||
}
|
||||
|
||||
return data.data.records || [];
|
||||
}
|
||||
|
||||
export async function loaddatabysqlApi(sql) {
|
||||
const { data } = await axios.get("/selectlistbysql", {
|
||||
params: {
|
||||
sql,
|
||||
},
|
||||
});
|
||||
|
||||
if (!data?.success) {
|
||||
throw new Error(data?.message || "查询失败");
|
||||
}
|
||||
|
||||
return data.data.records || [];
|
||||
}
|
||||
|
||||
export async function saveobjtApi(rows) {
|
||||
const { data } = await axios.post("/saveobjectV2", rows, {
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
|
||||
if (!data?.success) {
|
||||
throw new Error(data?.message || "保存失败");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
export default {
|
||||
getDataBySql,
|
||||
getDataBySqlPage,
|
||||
getMultipleDataBySql,
|
||||
};
|
||||
|
||||
// 导出单例
|
||||
@@ -0,0 +1,677 @@
|
||||
import { ElMessage } from "element-plus";
|
||||
import { nextTick, ref, unref } from "vue";
|
||||
import axios from "@/utils/axios";
|
||||
import { getDataBySql } from "@/utils/doSql";
|
||||
|
||||
const loading = ref(false);
|
||||
const saving = ref(false);
|
||||
const error = ref(null);
|
||||
|
||||
// export async function getTablePage({
|
||||
// tableName,
|
||||
// whereClause = '',
|
||||
// page = 1,
|
||||
// size = 20,
|
||||
// pkColumn = 'b_id desc',
|
||||
// moduleId = '',
|
||||
// }) {
|
||||
// try {
|
||||
// const { data } = await axios.get('/pagtable', {
|
||||
// params: {
|
||||
// tableName,
|
||||
// pkColumn,
|
||||
// page,
|
||||
// size,
|
||||
// whereClause,
|
||||
// moduleId,
|
||||
// },
|
||||
// })
|
||||
|
||||
// // 接口业务失败
|
||||
// if (!data?.success) {
|
||||
// return {
|
||||
// success: false,
|
||||
// records: [],
|
||||
// total: 0,
|
||||
// message: data?.message || '返回数据格式异常',
|
||||
// }
|
||||
// }
|
||||
|
||||
// const result = data?.data || {}
|
||||
|
||||
// return {
|
||||
// success: data?.success === true,
|
||||
// records: result.records || [],
|
||||
// total: result.total || 0,
|
||||
// message: data?.message || '',
|
||||
// raw: data,
|
||||
// }
|
||||
// }
|
||||
// catch (err) {
|
||||
// console.error('getTablePage Error:', err)
|
||||
|
||||
// return {
|
||||
// success: false,
|
||||
// records: [],
|
||||
// total: 0,
|
||||
// message: err?.message || '加载失败',
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* 获取分页表格数据
|
||||
*/
|
||||
export async function getTablePage({
|
||||
tableName,
|
||||
whereClause = "",
|
||||
page = 1,
|
||||
size = 20,
|
||||
pkColumn = "b_id desc",
|
||||
moduleId = "",
|
||||
targetRef = null,
|
||||
paginationTarget = null,
|
||||
errorRef = null,
|
||||
} = {}) {
|
||||
// ✅ 统一重置状态
|
||||
const resetState = (msg = "") => {
|
||||
if (targetRef) targetRef.value = [];
|
||||
if (paginationTarget) paginationTarget.total = 0;
|
||||
if (errorRef) errorRef.value = msg;
|
||||
};
|
||||
|
||||
try {
|
||||
if (!tableName) {
|
||||
throw new Error("tableName 不能为空");
|
||||
}
|
||||
|
||||
const { data } = await axios.get("/pagtable", {
|
||||
params: {
|
||||
tableName,
|
||||
pkColumn,
|
||||
page,
|
||||
size,
|
||||
whereClause,
|
||||
moduleId,
|
||||
},
|
||||
});
|
||||
|
||||
// ✅ 后端失败
|
||||
if (!data?.success) {
|
||||
const msg = data?.message || "获取数据失败";
|
||||
resetState(msg);
|
||||
return {
|
||||
success: false,
|
||||
records: [],
|
||||
total: 0,
|
||||
message: msg,
|
||||
};
|
||||
}
|
||||
|
||||
const { records = [], total = 0 } = data.data || {};
|
||||
|
||||
// ✅ 正常赋值
|
||||
if (targetRef) targetRef.value = records;
|
||||
if (paginationTarget) paginationTarget.total = total;
|
||||
if (errorRef) errorRef.value = null;
|
||||
|
||||
return {
|
||||
success: true,
|
||||
records,
|
||||
total,
|
||||
message: data.message || "ok",
|
||||
raw: data,
|
||||
};
|
||||
} catch (err) {
|
||||
console.error("[getTablePage Error]", err);
|
||||
resetState(err.message || "请求失败");
|
||||
return {
|
||||
success: false,
|
||||
records: [],
|
||||
total: 0,
|
||||
message: err.message || "请求失败",
|
||||
};
|
||||
}
|
||||
}
|
||||
// 获取表格列配置
|
||||
export async function getTableColumns(tableName) {
|
||||
try {
|
||||
loading.value = true;
|
||||
error.value = "";
|
||||
const response = await axios.get("/columns", {
|
||||
params: { tableName },
|
||||
});
|
||||
if (response.data?.success) {
|
||||
return {
|
||||
success: true,
|
||||
data: response.data.data,
|
||||
message: "列配置加载成功",
|
||||
};
|
||||
}
|
||||
throw new Error(response.data?.message || "返回数据格式异常");
|
||||
} catch (err) {
|
||||
error.value = `加载列配置失败: ${err.message}`;
|
||||
console.error("加载列配置错误:", err);
|
||||
return {
|
||||
success: false,
|
||||
data: [],
|
||||
error: err.message,
|
||||
};
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getColumnListConfig(tableName, targetRef) {
|
||||
try {
|
||||
// loaddata 接口
|
||||
loading.value = true;
|
||||
error.value = null;
|
||||
|
||||
const response = await axios.get("/columns", {
|
||||
params: { tableName },
|
||||
});
|
||||
|
||||
if (response.data?.success) {
|
||||
targetRef.value = response.data.data || [];
|
||||
} else {
|
||||
throw new Error(response.data?.message || "返回数据格式异常");
|
||||
}
|
||||
} catch (err) {
|
||||
error.value = `加载列配置失败: ${err.message}`;
|
||||
|
||||
console.error("加载列配置错误:", err);
|
||||
|
||||
targetRef.value = [];
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function setColumnListConfig(tableRefOrInstance, tableName) {
|
||||
await nextTick();
|
||||
// 关键:同时兼容 ref / 实例
|
||||
const table = unref(tableRefOrInstance);
|
||||
if (!table || typeof table.getColumns !== "function") {
|
||||
ElMessage.warning("表格尚未初始化完成");
|
||||
return;
|
||||
}
|
||||
|
||||
const columns = table.getColumns();
|
||||
if (!columns || columns.length === 0) {
|
||||
ElMessage.warning("未获取到栏位信息");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
saving.value = true;
|
||||
error.value = "";
|
||||
const newColumns = columns
|
||||
.filter((item) => item.field !== undefined)
|
||||
.map((item) => ({
|
||||
prop: item.field,
|
||||
width: item.renderWidth,
|
||||
col_TableName: tableName, // 或者你要的默认值
|
||||
}));
|
||||
|
||||
const response = await axios.post("/saveColumn", newColumns, {
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
if (response.data?.success) {
|
||||
ElMessage.success("保存成功");
|
||||
} else {
|
||||
throw new Error(response.data?.message || "保存失败");
|
||||
}
|
||||
} catch (err) {
|
||||
error.value = `保存失败: ${err.message}`;
|
||||
ElMessage.error("保存失败");
|
||||
} finally {
|
||||
saving.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getColumnconfig(tableName, targetRef) {
|
||||
try {
|
||||
loading.value = true;
|
||||
error.value = null;
|
||||
|
||||
const response = await axios.get("/columnsEdit", {
|
||||
params: { tableName },
|
||||
});
|
||||
if (response.data?.success) {
|
||||
// 直接对传入的响应式引用赋值
|
||||
targetRef.value = response.data.data;
|
||||
} else {
|
||||
throw new Error(response.data?.message || "返回数据格式异常");
|
||||
}
|
||||
} catch (err) {
|
||||
error.value = `加载列配置失败: ${err.message}`;
|
||||
// 出错时赋空数组
|
||||
targetRef.value = [];
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getSelectColumns(tableName, targetRef) {
|
||||
try {
|
||||
loading.value = true;
|
||||
error.value = null;
|
||||
const response = await axios.get("/columnsSelect", {
|
||||
params: { tableName },
|
||||
});
|
||||
if (response.data?.success) {
|
||||
targetRef.value = response.data.data;
|
||||
} else {
|
||||
throw new Error(response.data?.message || "返回数据格式异常");
|
||||
}
|
||||
} catch (err) {
|
||||
error.value = `加载列配置失败: ${err.message}`;
|
||||
targetRef.value = [];
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getTableColumnsEditDataset(tableName) {
|
||||
try {
|
||||
loading.value = true;
|
||||
error.value = "";
|
||||
const response = await axios.get("/columnsEdit", {
|
||||
params: { tableName },
|
||||
});
|
||||
if (response.data?.success) {
|
||||
return {
|
||||
success: true,
|
||||
data: response.data.data,
|
||||
message: "列配置加载成功",
|
||||
};
|
||||
}
|
||||
throw new Error(response.data?.message || "返回数据格式异常");
|
||||
} catch (err) {
|
||||
error.value = `加载列配置失败: ${err.message}`;
|
||||
console.error("加载列配置错误:", err);
|
||||
return {
|
||||
success: false,
|
||||
data: [],
|
||||
error: err.message,
|
||||
};
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getTableBatchEditColumns(tableName) {
|
||||
try {
|
||||
loading.value = true;
|
||||
error.value = "";
|
||||
const response = await axios.get("/columnsBatchEdit", {
|
||||
params: { tableName },
|
||||
});
|
||||
if (response.data?.success) {
|
||||
return {
|
||||
success: true,
|
||||
data: response.data.data,
|
||||
message: "列配置加载成功",
|
||||
};
|
||||
}
|
||||
throw new Error(response.data?.message || "返回数据格式异常");
|
||||
} catch (err) {
|
||||
error.value = `加载列配置失败: ${err.message}`;
|
||||
console.error("加载列配置错误:", err);
|
||||
return {
|
||||
success: false,
|
||||
data: [],
|
||||
error: err.message,
|
||||
};
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getMainTable(
|
||||
tableName,
|
||||
targetRef,
|
||||
originalRef,
|
||||
pkColumnValue,
|
||||
pkColumn = "b_id",
|
||||
) {
|
||||
try {
|
||||
loading.value = true;
|
||||
error.value = "";
|
||||
targetRef.value = {};
|
||||
|
||||
const params = {
|
||||
tableName: tableName || "v_bs_business",
|
||||
pkColumn,
|
||||
pkColumnValue,
|
||||
};
|
||||
const response = await axios.get("/getobject", { params });
|
||||
|
||||
if (response.data?.success) {
|
||||
const row = response.data.data || {};
|
||||
|
||||
if (Object.keys(row).length === 0) {
|
||||
ElMessage.warning("未找到对应记录");
|
||||
}
|
||||
|
||||
targetRef.value = { ...row };
|
||||
originalRef.value = { ...row };
|
||||
} else {
|
||||
throw new Error(response.data?.message || "返回数据格式异常");
|
||||
}
|
||||
} catch (err) {
|
||||
error.value = `加载客户详情失败: ${err.message}`;
|
||||
console.error("加载客户详情错误:", err);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getMainTableDataset(tableName, pkColumnValue) {
|
||||
try {
|
||||
loading.value = true;
|
||||
error.value = "";
|
||||
|
||||
const params = {
|
||||
tableName,
|
||||
pkColumn: "b_id",
|
||||
pkColumnValue,
|
||||
};
|
||||
|
||||
const response = await axios.get("/getobject", { params });
|
||||
|
||||
if (response.data?.success) {
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
current: { ...response.data.data },
|
||||
original: { ...response.data.data },
|
||||
},
|
||||
message: "主表数据加载成功",
|
||||
};
|
||||
}
|
||||
throw new Error(response.data?.message || "返回数据格式异常");
|
||||
} catch (err) {
|
||||
error.value = `加载主表数据失败: ${err.message}`;
|
||||
console.error("加载主表错误:", err);
|
||||
return {
|
||||
success: false,
|
||||
data: {
|
||||
current: null,
|
||||
original: null,
|
||||
},
|
||||
error: err.message,
|
||||
};
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getSubTable(tableName, targetRef, originalRef, whereClause) {
|
||||
try {
|
||||
loading.value = true;
|
||||
error.value = null;
|
||||
|
||||
const params = {
|
||||
tableName: tableName || "v_bs_business_container",
|
||||
pkColumn: "subid",
|
||||
whereClause,
|
||||
};
|
||||
const response = await axios.get("/pagdetail", { params });
|
||||
if (response.data?.success) {
|
||||
const rawData = JSON.parse(JSON.stringify(response.data.data.records || []));
|
||||
|
||||
targetRef.value = JSON.parse(JSON.stringify(rawData));
|
||||
originalRef.value = JSON.parse(JSON.stringify(rawData));
|
||||
} else {
|
||||
throw new Error(response.data?.message || "返回数据格式异常");
|
||||
}
|
||||
} catch (err) {
|
||||
error.value = `加载数据失败: ${err.message}`;
|
||||
console.error("API Error:", err);
|
||||
return { data: [], total: 0 };
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
// setColumnListConfig
|
||||
|
||||
export async function handleSaveColumn(tableRefOrInstance, tableName) {
|
||||
await nextTick();
|
||||
// 关键:同时兼容 ref / 实例
|
||||
const table = unref(tableRefOrInstance);
|
||||
if (!table || typeof table.getColumns !== "function") {
|
||||
ElMessage.warning("表格尚未初始化完成");
|
||||
return;
|
||||
}
|
||||
|
||||
const columns = table.getColumns();
|
||||
if (!columns || columns.length === 0) {
|
||||
ElMessage.warning("未获取到栏位信息");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
saving.value = true;
|
||||
error.value = "";
|
||||
const newColumns = columns
|
||||
.filter((item) => item.field !== undefined)
|
||||
.map((item) => ({
|
||||
prop: item.field,
|
||||
width: item.renderWidth,
|
||||
col_TableName: tableName, // 或者你要的默认值
|
||||
}));
|
||||
|
||||
const response = await axios.post("/saveColumn", newColumns, {
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
if (response.data?.success) {
|
||||
ElMessage.success("保存成功");
|
||||
} else {
|
||||
throw new Error(response.data?.message || "保存失败");
|
||||
}
|
||||
} catch (err) {
|
||||
error.value = `保存失败: ${err.message}`;
|
||||
ElMessage.error("保存失败");
|
||||
} finally {
|
||||
saving.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function handleSaveColumnEdit(tableRefOrInstance, tableName) {
|
||||
await nextTick();
|
||||
// 关键:同时兼容 ref / 实例
|
||||
const table = unref(tableRefOrInstance);
|
||||
if (!table || typeof table.getColumns !== "function") {
|
||||
ElMessage.warning("表格尚未初始化完成");
|
||||
return;
|
||||
}
|
||||
|
||||
const columns = table.getColumns();
|
||||
if (!columns || columns.length === 0) {
|
||||
ElMessage.warning("未获取到栏位信息");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
saving.value = true;
|
||||
error.value = "";
|
||||
const newColumns = columns
|
||||
.filter((item) => item.field !== undefined)
|
||||
.map((item) => ({
|
||||
prop: item.field,
|
||||
edit_width: item.renderWidth,
|
||||
col_TableName: tableName, // 或者你要的默认值
|
||||
}));
|
||||
// console.log(newColumns)
|
||||
const response = await axios.post("/saveColumnEdit", newColumns, {
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
if (response.data?.success) {
|
||||
ElMessage.success("保存成功");
|
||||
} else {
|
||||
throw new Error(response.data?.message || "保存失败");
|
||||
}
|
||||
} catch (err) {
|
||||
error.value = `保存失败: ${err.message}`;
|
||||
ElMessage.error("保存失败");
|
||||
} finally {
|
||||
saving.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getTableLabelEdit(tableName) {
|
||||
const res = await getDataBySql(
|
||||
`select * from s_columnLib WHERE col_TableName = '${tableName}' and col_edit='1' order by col_edit_position`,
|
||||
);
|
||||
const map = Object.create(null);
|
||||
|
||||
const records = res?.records || [];
|
||||
|
||||
records.forEach((col) => {
|
||||
if (col?.col_FieldName) {
|
||||
map[col.col_FieldName] = {
|
||||
caption: col.col_Caption || "",
|
||||
required: col.col_AllowNull !== "1",
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
// export async function handleMappingConfig(selectId, whereDataset, whereClause, targetRef, originalRef) {
|
||||
// let selectSql = ''
|
||||
// let selectOrder = ''
|
||||
// const data_selectsql = await getDataBySql(`select * from s_selectsql where selectid='${selectId}' `)
|
||||
// if (data_selectsql.records.length > 0) {
|
||||
// selectSql = data_selectsql.records[0].selectsql
|
||||
// selectOrder = data_selectsql.records[0].orderfield
|
||||
// }
|
||||
// whereDataset = unref(whereDataset)
|
||||
// for (const key in whereDataset) {
|
||||
// const v = (whereDataset[key] ?? '').toString().trim()
|
||||
|
||||
// const regex = new RegExp(
|
||||
// `\\s+and\\s+[^\\s]+\\s*(=|like)\\s*:${escapeRegExp(key)}\\b`,
|
||||
// 'gi',
|
||||
// )
|
||||
|
||||
// if (v === '') {
|
||||
// selectSql = selectSql.replace(regex, '')
|
||||
// }
|
||||
// else {
|
||||
// selectSql = selectSql.replaceAll(
|
||||
// `:${key}`,
|
||||
// `'${v.replaceAll('\'', '\'\'')}'`,
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
|
||||
// let sql = `${selectSql} ${whereClause} order by ${selectOrder}`
|
||||
// console.log('sql=----------')
|
||||
// console.log(sql)
|
||||
|
||||
// const data = await getDataBySql(sql)
|
||||
// if (data.records.length == 0) {
|
||||
// ElMessage.warning('数据不存在!')
|
||||
// return
|
||||
// }
|
||||
|
||||
// const data_selectdatamap = await getDataBySql(`select * from s_selectdatamap where selectid='${selectId}' `)
|
||||
// if (data_selectdatamap.records.length > 0) {
|
||||
// const maps = data_selectdatamap?.records || []
|
||||
|
||||
// const resultList = data.records.map((row) => {
|
||||
// const obj = {}
|
||||
// maps.forEach((item) => {
|
||||
// obj[item.des_field] = row[item.source_field]
|
||||
// })
|
||||
// return obj
|
||||
// })
|
||||
// // console.log('resultList=-=-=-=-=-')
|
||||
// // console.log(resultList)
|
||||
// // subtable.value = resultList
|
||||
// // subtableoriginal.value = resultList
|
||||
// targetRef.value = [
|
||||
// ...targetRef.value,
|
||||
// ...JSON.parse(JSON.stringify(resultList)),
|
||||
// ]
|
||||
// }
|
||||
// }
|
||||
|
||||
export async function handleMappingConfig(selectId, subidliststr, targetRef) {
|
||||
let selectSql = "";
|
||||
let selectOrder = "";
|
||||
const data_selectsql = await getDataBySql(
|
||||
`select * from s_selectsql where selectid='${selectId}' `,
|
||||
);
|
||||
if (data_selectsql.records.length > 0) {
|
||||
selectSql = data_selectsql.records[0].selectsql;
|
||||
}
|
||||
|
||||
let sql = `${selectSql} ${subidliststr} `;
|
||||
console.log("sql=----------");
|
||||
console.log(sql);
|
||||
|
||||
const data = await getDataBySql(sql);
|
||||
if (data.records.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const data_selectdatamap = await getDataBySql(
|
||||
`select * from s_selectdatamap where selectid='${selectId}' `,
|
||||
);
|
||||
if (data_selectdatamap.records.length > 0) {
|
||||
const maps = data_selectdatamap?.records || [];
|
||||
|
||||
const resultList = data.records.map((row) => {
|
||||
const obj = {};
|
||||
maps.forEach((item) => {
|
||||
obj[item.des_field] = row[item.source_field];
|
||||
});
|
||||
return obj;
|
||||
});
|
||||
targetRef.value = [...targetRef.value, ...JSON.parse(JSON.stringify(resultList))];
|
||||
}
|
||||
}
|
||||
|
||||
function escapeRegExp(str) {
|
||||
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||||
}
|
||||
|
||||
export const editableStates = ["草拟", "审核驳回", "送审"];
|
||||
// 是否可编辑
|
||||
export function isEditableState(state) {
|
||||
return editableStates.includes(state || "");
|
||||
}
|
||||
|
||||
// 审核通过状态
|
||||
export const approvedStates = ["审核通过"];
|
||||
// 是否审核通过
|
||||
export function isApprovedState(state) {
|
||||
return !approvedStates.includes(state || "");
|
||||
}
|
||||
|
||||
export default {
|
||||
getTablePage,
|
||||
getTableColumns,
|
||||
getColumnListConfig,
|
||||
setColumnListConfig,
|
||||
getColumnconfig,
|
||||
getSelectColumns,
|
||||
getTableColumnsEditDataset,
|
||||
getTableBatchEditColumns,
|
||||
getMainTable,
|
||||
getMainTableDataset,
|
||||
getSubTable,
|
||||
handleSaveColumn,
|
||||
handleSaveColumnEdit,
|
||||
getTableLabelEdit,
|
||||
handleMappingConfig,
|
||||
isEditableState,
|
||||
isApprovedState,
|
||||
};
|
||||
|
||||
// 导出单例
|
||||
@@ -0,0 +1,342 @@
|
||||
import ExcelJS from "exceljs";
|
||||
import { VxeUI } from "vxe-pc-ui";
|
||||
import { formatValueByFullFormat, getAlignByFormat, updateTableFooterData } from "@/utils/column";
|
||||
|
||||
export function ExportVxeTableExcel(tableRef) {
|
||||
if (!tableRef) {
|
||||
return;
|
||||
}
|
||||
|
||||
// columns
|
||||
const fullColumns = tableRef.getFullColumns();
|
||||
const exportColumns = buildColumns(fullColumns) || [];
|
||||
const exportDatas =
|
||||
tableRef.getCheckboxRecords().length > 0
|
||||
? tableRef.getCheckboxRecords()
|
||||
: tableRef.getFullData();
|
||||
|
||||
const footerDatas = updateTableFooterData(exportColumns, exportDatas);
|
||||
|
||||
ExportExcel(exportColumns, exportDatas, footerDatas);
|
||||
}
|
||||
|
||||
export function ExportExcel(columns, data, footerData = []) {
|
||||
const workbook = new ExcelJS.Workbook();
|
||||
const sheet = workbook.addWorksheet("Sheet1");
|
||||
|
||||
const exportColumns = columns;
|
||||
const exportDatas = data;
|
||||
|
||||
if (!exportColumns || exportColumns.length === 0) {
|
||||
console.error("没有找到列数据");
|
||||
return;
|
||||
}
|
||||
|
||||
VxeUI.modal.message({
|
||||
content: `正在导出中 . . .`,
|
||||
status: "loading",
|
||||
duration: -1,
|
||||
});
|
||||
|
||||
// 1. 提取所有叶子节点(数据列)
|
||||
const leafColumns = [];
|
||||
const headerData = [];
|
||||
const mergeInfo = [];
|
||||
|
||||
// 2. 解析列结构,构建表头数据
|
||||
function parseColumns(cols, currentLevel = 0, startCol = 0) {
|
||||
let colIndex = startCol;
|
||||
|
||||
cols.forEach((col) => {
|
||||
// 确保当前层级的数组存在
|
||||
if (!headerData[currentLevel]) {
|
||||
headerData[currentLevel] = [];
|
||||
}
|
||||
|
||||
if (col.children && col.children.length > 0) {
|
||||
// 处理有子级的列
|
||||
const childLeafCount = parseColumns(col.children, currentLevel + 1, colIndex);
|
||||
|
||||
// 记录合并信息(水平合并)
|
||||
if (childLeafCount > 1) {
|
||||
mergeInfo.push({
|
||||
startRow: currentLevel + 1, // ExcelJS 行号从1开始
|
||||
startCol: colIndex + 1, // ExcelJS 列号从1开始
|
||||
endRow: currentLevel + 1,
|
||||
endCol: colIndex + childLeafCount,
|
||||
});
|
||||
}
|
||||
|
||||
// 设置当前行的表头
|
||||
headerData[currentLevel][colIndex] = col.label || "";
|
||||
|
||||
// 填充子级占据的列
|
||||
for (let i = 1; i < childLeafCount; i++) {
|
||||
headerData[currentLevel][colIndex + i] = "";
|
||||
}
|
||||
|
||||
colIndex += childLeafCount;
|
||||
} else {
|
||||
// 处理叶子节点
|
||||
leafColumns.push(col);
|
||||
|
||||
// 设置当前行和所有下层的表头
|
||||
for (let level = currentLevel; level < headerData.length; level++) {
|
||||
if (!headerData[level]) headerData[level] = [];
|
||||
if (level === currentLevel) {
|
||||
headerData[level][colIndex] = col.label || "";
|
||||
} else {
|
||||
headerData[level][colIndex] = col.label || ""; // 对于垂直合并,需要填充标签
|
||||
}
|
||||
}
|
||||
|
||||
// 记录垂直合并信息
|
||||
if (headerData.length - currentLevel > 1) {
|
||||
mergeInfo.push({
|
||||
startRow: currentLevel + 1,
|
||||
startCol: colIndex + 1,
|
||||
endRow: headerData.length, // 合并到最后一行
|
||||
endCol: colIndex + 1,
|
||||
});
|
||||
}
|
||||
|
||||
colIndex++;
|
||||
}
|
||||
});
|
||||
|
||||
return colIndex - startCol; // 返回该组列占用的列数
|
||||
}
|
||||
|
||||
// 初始化 headerData 数组
|
||||
const maxDepth = getMaxDepth(exportColumns);
|
||||
for (let i = 0; i < maxDepth; i++) {
|
||||
headerData[i] = [];
|
||||
}
|
||||
|
||||
parseColumns(exportColumns);
|
||||
|
||||
// 3. 添加表头行
|
||||
headerData.forEach((rowData, rowIndex) => {
|
||||
const row = sheet.addRow(rowData);
|
||||
|
||||
// 设置表头样式
|
||||
row.eachCell((cell, colNumber) => {
|
||||
cell.style = {
|
||||
font: { bold: true, size: 10 },
|
||||
alignment: { horizontal: "center", vertical: "middle" },
|
||||
fill: {
|
||||
type: "pattern",
|
||||
pattern: "solid",
|
||||
fgColor: { argb: "FFE0E0E0" },
|
||||
},
|
||||
border: {
|
||||
top: { style: "thin" },
|
||||
left: { style: "thin" },
|
||||
bottom: { style: "thin" },
|
||||
right: { style: "thin" },
|
||||
},
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
// 4. 合并单元格(先排序,避免重复合并)
|
||||
// 按照从左上到右下的顺序排序
|
||||
mergeInfo.sort((a, b) => {
|
||||
if (a.startRow !== b.startRow) return a.startRow - b.startRow;
|
||||
return a.startCol - b.startCol;
|
||||
});
|
||||
|
||||
// 记录已合并的单元格
|
||||
const mergedCells = new Set();
|
||||
|
||||
mergeInfo.forEach((merge) => {
|
||||
// 检查这个合并区域是否与已合并的区域冲突
|
||||
let canMerge = true;
|
||||
for (let r = merge.startRow; r <= merge.endRow; r++) {
|
||||
for (let c = merge.startCol; c <= merge.endCol; c++) {
|
||||
const cellKey = `${r}-${c}`;
|
||||
if (mergedCells.has(cellKey)) {
|
||||
canMerge = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!canMerge) break;
|
||||
}
|
||||
|
||||
if (canMerge) {
|
||||
try {
|
||||
sheet.mergeCells(merge.startRow, merge.startCol, merge.endRow, merge.endCol);
|
||||
|
||||
// 记录已合并的单元格
|
||||
for (let r = merge.startRow; r <= merge.endRow; r++) {
|
||||
for (let c = merge.startCol; c <= merge.endCol; c++) {
|
||||
mergedCells.add(`${r}-${c}`);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
`无法合并单元格 ${merge.startRow}:${merge.startCol}-${merge.endRow}:${merge.endCol}`,
|
||||
error,
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 5. 设置列宽
|
||||
sheet.columns = leafColumns.map((col) => ({
|
||||
key: col.prop,
|
||||
width: pxToExcelWidth(col.width) || 20,
|
||||
}));
|
||||
|
||||
// 6. 填充数据
|
||||
exportDatas.forEach((item, rowIndex) => {
|
||||
const rowData = {};
|
||||
|
||||
leafColumns.forEach((col, colIndex) => {
|
||||
let value = item[col.prop];
|
||||
|
||||
// 如果是空值,设置为空字符串
|
||||
rowData[col.prop] = formatValueByFullFormat(value, col.displayFormat);
|
||||
});
|
||||
|
||||
const row = sheet.addRow(rowData);
|
||||
|
||||
// 设置数据行样式
|
||||
row.eachCell((cell, colNumber) => {
|
||||
const leafCol = leafColumns[colNumber - 1];
|
||||
|
||||
const style = {
|
||||
font: { size: 10 },
|
||||
alignment: { vertical: "middle" },
|
||||
border: {
|
||||
top: { style: "thin" },
|
||||
left: { style: "thin" },
|
||||
bottom: { style: "thin" },
|
||||
right: { style: "thin" },
|
||||
},
|
||||
};
|
||||
|
||||
style.alignment.horizontal = getAlignByFormat(leafCol.displayFormat);
|
||||
cell.style = style;
|
||||
});
|
||||
});
|
||||
|
||||
// 7. 添加汇总行
|
||||
if (footerData.length > 0) {
|
||||
footerData.forEach((footerItem, rowIndex) => {
|
||||
const summaryRowData = {};
|
||||
|
||||
// 遍历所有列,计算每个列的汇总值
|
||||
leafColumns.forEach((col) => {
|
||||
summaryRowData[col.prop] = formatValueByFullFormat(footerItem[col.prop], col.displayFormat);
|
||||
});
|
||||
|
||||
// 添加汇总行
|
||||
const summaryRow = sheet.addRow(summaryRowData);
|
||||
|
||||
summaryRow.eachCell((cell) => {
|
||||
// 设置单元格样式
|
||||
const style = {
|
||||
font: { bold: true, size: 10 },
|
||||
alignment: { vertical: "middle" },
|
||||
fill: {
|
||||
type: "pattern",
|
||||
pattern: "solid",
|
||||
fgColor: { argb: "FFF0F0F0" },
|
||||
},
|
||||
border: {
|
||||
top: { style: "thin" },
|
||||
left: { style: "thin" },
|
||||
bottom: { style: "thin" },
|
||||
right: { style: "thin" },
|
||||
},
|
||||
};
|
||||
style.alignment.horizontal = "right";
|
||||
|
||||
// 应用样式
|
||||
cell.style = style;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 8. 保存文件
|
||||
workbook.xlsx
|
||||
.writeBuffer()
|
||||
.then((buffer) => {
|
||||
const blob = new Blob([buffer], {
|
||||
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
});
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const link = document.createElement("a");
|
||||
link.href = url;
|
||||
link.download = `export-${new Date().getTime()}.xlsx`;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
window.URL.revokeObjectURL(url);
|
||||
|
||||
VxeUI.modal.close();
|
||||
|
||||
VxeUI.modal.message({
|
||||
content: `导出成功`,
|
||||
status: "success",
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("生成 Excel 文件失败:", err);
|
||||
|
||||
VxeUI.modal.message({
|
||||
content: `导出失败`,
|
||||
status: "error",
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 获取最大深度
|
||||
function getMaxDepth(columns, currentDepth = 1) {
|
||||
let maxDepth = currentDepth;
|
||||
|
||||
columns.forEach((col) => {
|
||||
if (col.children && col.children.length > 0) {
|
||||
const childDepth = getMaxDepth(col.children, currentDepth + 1);
|
||||
maxDepth = Math.max(maxDepth, childDepth);
|
||||
}
|
||||
});
|
||||
|
||||
return maxDepth;
|
||||
}
|
||||
|
||||
function pxToExcelWidth(px) {
|
||||
return Number(px) / 8;
|
||||
}
|
||||
|
||||
function buildColumns(arr) {
|
||||
return arr
|
||||
.filter((item) => {
|
||||
if (
|
||||
(item.type === "checkbox" || item.type === "seq") &&
|
||||
(!item.children || item.children.length === 0)
|
||||
) {
|
||||
return false;
|
||||
} else if (item.title === "操作") {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.map((item) => {
|
||||
let column = {};
|
||||
|
||||
if (item.params) {
|
||||
column = { ...item.params };
|
||||
}
|
||||
|
||||
column.label = item.title;
|
||||
column.width = item.renderWidth || item.width;
|
||||
|
||||
if (item.children && item.children.length > 0) {
|
||||
column.children = buildColumns(item.children);
|
||||
}
|
||||
|
||||
return column;
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,379 @@
|
||||
import { ElMessage } from "element-plus";
|
||||
import { saveAs } from "file-saver";
|
||||
import JSZip from "jszip";
|
||||
import {
|
||||
closeUploadProgress,
|
||||
showUploadProgress,
|
||||
updateUploadProgress,
|
||||
} from "@/components/upload-progress/index";
|
||||
import axios from "@/utils/axios";
|
||||
|
||||
const AliyunBucket = "g3hy";
|
||||
|
||||
export function getAliyunKeyApi() {
|
||||
return axios.get("/file/getAliyunKey", {
|
||||
params: {
|
||||
bucket: AliyunBucket,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function insertFileApi(data) {
|
||||
return axios.post("/file/insert", data);
|
||||
}
|
||||
|
||||
export function deleteFileApi(tableName, id) {
|
||||
return axios.post("/file/delete", {
|
||||
tableName,
|
||||
bucketName: AliyunBucket,
|
||||
id,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择并压缩图片
|
||||
*/
|
||||
export function uploadImage(options = {}) {
|
||||
const { quality = 0.9, maxSize = 512000 } = options;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
if (typeof document === "undefined") {
|
||||
reject(new Error("Require browser environment"));
|
||||
return;
|
||||
}
|
||||
|
||||
const input = document.createElement("input");
|
||||
input.type = "file";
|
||||
input.accept = "image/*";
|
||||
input.style.display = "none";
|
||||
|
||||
input.onchange = async (e) => {
|
||||
const file = e.target.files?.[0];
|
||||
if (!file) {
|
||||
reject(new Error("No file selected"));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!file.type.startsWith("image/")) {
|
||||
throw new Error("Invalid image file");
|
||||
}
|
||||
|
||||
// 创建一个临时URL来加载图片
|
||||
const url = URL.createObjectURL(file);
|
||||
|
||||
// 调用 compressImage 进行压缩
|
||||
const compressResult = await compressImage(url, quality, maxSize);
|
||||
|
||||
// 释放临时URL
|
||||
URL.revokeObjectURL(url);
|
||||
|
||||
resolve({
|
||||
blob: compressResult.blob,
|
||||
url: compressResult.url,
|
||||
fileName: file.name,
|
||||
fileExt: getFileExtension(file.name),
|
||||
fileSize: file.size,
|
||||
});
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
} finally {
|
||||
document.body.removeChild(input);
|
||||
}
|
||||
};
|
||||
|
||||
document.body.appendChild(input);
|
||||
input.click();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择视频
|
||||
*/
|
||||
export function uploadVideo() {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (typeof document === "undefined") {
|
||||
reject(new Error("Require browser environment"));
|
||||
return;
|
||||
}
|
||||
|
||||
const input = document.createElement("input");
|
||||
input.type = "file";
|
||||
input.accept = "video/*";
|
||||
input.style.display = "none";
|
||||
|
||||
input.onchange = (e) => {
|
||||
const file = e.target.files?.[0];
|
||||
if (!file) {
|
||||
reject(new Error("No file selected"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!file.type.startsWith("video/")) {
|
||||
reject(new Error("Invalid video file"));
|
||||
return;
|
||||
}
|
||||
|
||||
resolve({
|
||||
blob: file,
|
||||
url: URL.createObjectURL(file),
|
||||
fileName: file.name,
|
||||
fileExt: getFileExtension(file.name),
|
||||
fileSize: file.size,
|
||||
});
|
||||
|
||||
document.body.removeChild(input);
|
||||
};
|
||||
|
||||
document.body.appendChild(input);
|
||||
input.click();
|
||||
});
|
||||
}
|
||||
|
||||
// 压缩图片
|
||||
export async function compressImage(url, quality = 0.9, maxSize = 512000) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const img = new Image();
|
||||
img.src = url;
|
||||
|
||||
img.onload = async () => {
|
||||
try {
|
||||
// 获取原图大小
|
||||
const imgSize = await fetch(url)
|
||||
.then((res) => res.blob())
|
||||
.then((blob) => blob.size);
|
||||
|
||||
if (imgSize <= maxSize) {
|
||||
return resolve({ url, size: imgSize, blob: await fetch(url).then((res) => res.blob()) });
|
||||
}
|
||||
const canvas = document.createElement("canvas");
|
||||
const ctx = canvas.getContext("2d");
|
||||
if (!ctx) return reject(new Error("无法获取canvas上下文"));
|
||||
|
||||
let targetWidth = img.width;
|
||||
let targetHeight = img.height;
|
||||
|
||||
// 最大边长限制
|
||||
const maxEdge = 2000;
|
||||
if (targetWidth > maxEdge || targetHeight > maxEdge) {
|
||||
if (targetWidth > targetHeight) {
|
||||
targetHeight = (maxEdge * targetHeight) / targetWidth;
|
||||
targetWidth = maxEdge;
|
||||
} else {
|
||||
targetWidth = (maxEdge * targetWidth) / targetHeight;
|
||||
targetHeight = maxEdge;
|
||||
}
|
||||
}
|
||||
|
||||
canvas.width = targetWidth;
|
||||
canvas.height = targetHeight;
|
||||
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
ctx.drawImage(img, 0, 0, targetWidth, targetHeight);
|
||||
|
||||
const getBlob = (q) =>
|
||||
new Promise((resolve, reject) => {
|
||||
canvas.toBlob(
|
||||
(blob) => (blob ? resolve(blob) : reject(new Error("Blob转换失败"))),
|
||||
"image/jpeg",
|
||||
q,
|
||||
);
|
||||
});
|
||||
|
||||
let blob = await getBlob(quality);
|
||||
|
||||
// 调整质量直到接近最大文件大小
|
||||
let minQ = 0.5;
|
||||
let maxQ = quality;
|
||||
let attempts = 0;
|
||||
|
||||
while (blob.size > maxSize && maxQ - minQ > 0.01 && attempts < 5) {
|
||||
const midQ = (minQ + maxQ) / 2;
|
||||
blob = await getBlob(midQ);
|
||||
if (blob.size > maxSize) {
|
||||
maxQ = midQ;
|
||||
} else {
|
||||
minQ = midQ;
|
||||
}
|
||||
attempts++;
|
||||
}
|
||||
resolve({ blob, size: blob.size, url: URL.createObjectURL(blob) });
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
}
|
||||
};
|
||||
|
||||
img.onerror = () => reject(new Error("图片加载失败"));
|
||||
});
|
||||
}
|
||||
|
||||
export function formatFileSize(size) {
|
||||
if (size < 1024) return `${size} B`;
|
||||
else if (size < 1024 * 1024) return `${(size / 1024).toFixed(2)} KB`;
|
||||
else if (size < 1024 * 1024 * 1024) return `${(size / (1024 * 1024)).toFixed(2)} MB`;
|
||||
else return `${(size / (1024 * 1024 * 1024)).toFixed(2)} GB`;
|
||||
}
|
||||
|
||||
// 获取文件扩展名并进行分类
|
||||
export function getFileExtension(fileName) {
|
||||
// 获取文件扩展名
|
||||
const fileExt = fileName.includes(".")
|
||||
? fileName.slice(fileName.lastIndexOf(".") + 1).toLowerCase() // 获取扩展名并转为小写
|
||||
: "";
|
||||
|
||||
// 如果是office类文件,将其归类到 "office"
|
||||
if (["docx", "docm", "xls", "xlsx"].includes(fileExt)) {
|
||||
return "office";
|
||||
}
|
||||
|
||||
// 返回扩展名
|
||||
return fileExt;
|
||||
}
|
||||
|
||||
// 上传到阿里云
|
||||
// blob fileName fileSize xh moduleid father cateid
|
||||
export function uploadFile(blob, fileName, fileExt, fileSize, xh, moduleid, father, cateid) {
|
||||
return new Promise((resolve, reject) => {
|
||||
getAliyunKeyApi()
|
||||
.then(async (res) => {
|
||||
try {
|
||||
const aliyunKey = res.data.data;
|
||||
const formData = new FormData();
|
||||
|
||||
let uniqueName = `${Date.now()}_${Math.random().toString(36).slice(2)}`;
|
||||
|
||||
if (fileExt) {
|
||||
uniqueName += `.${fileExt}`;
|
||||
}
|
||||
|
||||
formData.append("key", `${aliyunKey.dir}${uniqueName}`);
|
||||
formData.append("OSSAccessKeyId", aliyunKey.accessid);
|
||||
formData.append("policy", aliyunKey.policy);
|
||||
formData.append("Signature", aliyunKey.signature);
|
||||
formData.append("file", blob, uniqueName);
|
||||
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", aliyunKey.host, true);
|
||||
|
||||
xhr.onload = async () => {
|
||||
if (xhr.status === 200 || xhr.status === 204) {
|
||||
const allFilePath = `${aliyunKey.host}/${aliyunKey.dir}${uniqueName}`;
|
||||
|
||||
const insertRes = await insertFileApi({
|
||||
father,
|
||||
mx_moduleid: moduleid,
|
||||
mx_xh: xh,
|
||||
mx_filename: fileName,
|
||||
mx_mapfilename: allFilePath,
|
||||
mx_filesize: fileSize,
|
||||
mx_fileext: fileExt,
|
||||
mx_cate_id: cateid || "",
|
||||
});
|
||||
|
||||
if (insertRes.data.success) {
|
||||
resolve({
|
||||
father,
|
||||
mx_moduleid: moduleid,
|
||||
mx_xh: xh,
|
||||
mx_filename: fileName,
|
||||
mx_mapfilename: allFilePath,
|
||||
mx_filesize: fileSize,
|
||||
mx_fileext: fileExt,
|
||||
mx_cate_id: cateid || "",
|
||||
});
|
||||
} else {
|
||||
reject(new Error(insertRes.data.message));
|
||||
}
|
||||
} else {
|
||||
ElMessage.error("上传失败,请稍后再试");
|
||||
reject(new Error(`OSS 上传失败: ${xhr.responseText}`));
|
||||
}
|
||||
};
|
||||
|
||||
xhr.onerror = () => {
|
||||
ElMessage.error("上传失败,请稍后再试");
|
||||
reject(new Error("OSS 上传异常"));
|
||||
};
|
||||
|
||||
xhr.send(formData);
|
||||
} catch (err) {
|
||||
ElMessage.error("上传失败,请稍后再试");
|
||||
reject(err);
|
||||
}
|
||||
})
|
||||
.catch(reject);
|
||||
});
|
||||
}
|
||||
|
||||
export function getAliyunFileBlob(url) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 创建一个独立的异步函数来处理 fetch 请求
|
||||
async function fetchFile() {
|
||||
try {
|
||||
const response = await fetch(url, { mode: "cors" });
|
||||
|
||||
// 检查响应状态
|
||||
if (!response.ok) {
|
||||
ElMessage.error(`下载失败:${response.status}`);
|
||||
reject(new Error(`下载失败:${response.status}`));
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取文件内容
|
||||
const blob = await response.blob();
|
||||
|
||||
// 返回blob
|
||||
resolve(blob);
|
||||
} catch (error) {
|
||||
// 捕获网络请求失败或其他错误
|
||||
ElMessage.error("下载文件时发生错误");
|
||||
reject(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 调用异步函数
|
||||
fetchFile();
|
||||
});
|
||||
}
|
||||
|
||||
export function downloadZip(files, fileName = "文件合集", callback) {
|
||||
const zip = new JSZip();
|
||||
const addedFiles = new Set(); // 用来存储已添加的文件名
|
||||
|
||||
let result = files.map((item) => {
|
||||
let promise = getAliyunFileBlob(item.mx_mapfilename).then((res) => {
|
||||
// 处理文件名重复的情况
|
||||
let uniqueFileName = getUniqueFileName(item.mx_filename, addedFiles);
|
||||
zip.file(uniqueFileName, res, { binary: true });
|
||||
addedFiles.add(uniqueFileName); // 添加文件名到已添加的集合中
|
||||
});
|
||||
return promise;
|
||||
});
|
||||
|
||||
Promise.all(result)
|
||||
.then(() => {
|
||||
zip.generateAsync({ type: "blob" }).then((res) => {
|
||||
callback && callback();
|
||||
saveAs(res, `${fileName}.zip`);
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
callback && callback();
|
||||
});
|
||||
}
|
||||
|
||||
// 处理文件名重复的函数
|
||||
function getUniqueFileName(fileName, addedFiles) {
|
||||
let uniqueFileName = fileName;
|
||||
let counter = 1;
|
||||
|
||||
// 如果文件名已经存在,则在文件名后加上 (1), (2), ...
|
||||
while (addedFiles.has(uniqueFileName)) {
|
||||
const fileNameWithoutExtension = uniqueFileName.replace(/\.[^/.]+$/, "");
|
||||
const extension = uniqueFileName.slice(uniqueFileName.lastIndexOf("."));
|
||||
uniqueFileName = `${fileNameWithoutExtension} (${counter})${extension}`;
|
||||
counter++;
|
||||
}
|
||||
|
||||
return uniqueFileName;
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
import { ElMessage } from "element-plus";
|
||||
import { ref, unref } from "vue";
|
||||
import axios from "@/utils/axios";
|
||||
import { useUserStore } from "@/store/user";
|
||||
|
||||
const userStore = useUserStore();
|
||||
|
||||
const loading = ref(false);
|
||||
const saving = ref(false);
|
||||
const error = ref(null);
|
||||
|
||||
export async function getDefaultValue(targetRef, tablename) {
|
||||
try {
|
||||
loading.value = true;
|
||||
error.value = null;
|
||||
const params = {
|
||||
tableName: tablename || "v_bs_business",
|
||||
};
|
||||
const response = await axios.get("/getDefaultvalue", { params });
|
||||
if (response.data?.success) {
|
||||
//targetRef.value = JSON.parse(JSON.stringify(response.data.data || []));
|
||||
console.log("response.data.data=-=-=-");
|
||||
console.log(response.data.data);
|
||||
Object.assign(targetRef.value, response.data.data);
|
||||
} else {
|
||||
throw new Error(response.data?.message || "返回数据格式异常");
|
||||
}
|
||||
} catch (err) {
|
||||
error.value = `加载数据失败: ${err.message}`;
|
||||
console.error("API Error:", err);
|
||||
return { data: [], total: 0 };
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function checkMustField(targetObj, tablename) {
|
||||
const targetdata = unref(targetObj);
|
||||
const params = {
|
||||
tableName: tablename || "v_bs_business",
|
||||
};
|
||||
|
||||
const response = await axios.get("/getMustfield", { params });
|
||||
|
||||
if (!response.data?.success) {
|
||||
throw new Error(response.data?.message || "返回数据格式异常");
|
||||
}
|
||||
|
||||
const mustFields = response.data.data || [];
|
||||
|
||||
for (const field of mustFields) {
|
||||
const fieldName = field.col_FieldName;
|
||||
const value = targetdata[fieldName];
|
||||
console.log(value);
|
||||
|
||||
if (value === null || value === undefined || String(value).trim() === "") {
|
||||
const caption = field.col_Caption || fieldName;
|
||||
ElMessage.error(`${caption} 不能为空`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export async function getMoneyExRate({
|
||||
rows = [],
|
||||
field = "v_mx_moneytype_id",
|
||||
defaultMoney = "RMB",
|
||||
tableName = "b_money",
|
||||
moneyField = "b_name",
|
||||
rateField = "b_hl",
|
||||
} = {}) {
|
||||
let exrate = 1;
|
||||
|
||||
if (!Array.isArray(rows) || rows.length === 0) {
|
||||
return exrate;
|
||||
}
|
||||
|
||||
const row = rows.find((item) => item[field] && item[field] !== defaultMoney);
|
||||
|
||||
if (!row) {
|
||||
return exrate;
|
||||
}
|
||||
|
||||
const moneyid = row[field];
|
||||
|
||||
const sql = `
|
||||
select ${rateField}
|
||||
from ${tableName}
|
||||
where ${moneyField}='${moneyid}'
|
||||
`;
|
||||
|
||||
const res = await getDataBySql(sql);
|
||||
|
||||
if (res?.records?.length > 0) {
|
||||
exrate = Number(res.records[0][rateField]) || 1;
|
||||
}
|
||||
|
||||
return exrate;
|
||||
}
|
||||
|
||||
export function toMoney(val, scale = 3) {
|
||||
const num = Number(val || 0);
|
||||
|
||||
if (isNaN(num)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Number(num.toFixed(scale));
|
||||
}
|
||||
|
||||
export const editableStates = ["草拟", "审核驳回", "送审"];
|
||||
export function isEditableStateAndQR(state, cwqr) {
|
||||
return editableStates.includes(state || "") && String(cwqr) !== "1";
|
||||
}
|
||||
|
||||
export function isNotEmpty(val) {
|
||||
return val !== null && val !== undefined && String(val).trim() !== "";
|
||||
}
|
||||
|
||||
export function getFieldString(arr, field, limit = 100) {
|
||||
return [...new Set(arr.map((item) => item[field]).filter(Boolean))].slice(0, limit).join(",");
|
||||
}
|
||||
|
||||
export function morePermission(permissionId) {
|
||||
const userStore = useUserStore();
|
||||
return !userStore.hasActionPermission(permissionId);
|
||||
}
|
||||
|
||||
// 默认导出所有方法
|
||||
export default {
|
||||
getDefaultValue,
|
||||
checkMustField,
|
||||
getMoneyExRate,
|
||||
toMoney,
|
||||
isEditableStateAndQR,
|
||||
isNotEmpty,
|
||||
getFieldString,
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
export function processGridKeydown(event, $table) {
|
||||
if (!$table) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentRow = $table.getCurrentRecord();
|
||||
const currentRowIndex = $table.getRowIndex(currentRow);
|
||||
const currentColumn = $table.getCurrentColumn();
|
||||
const { key } = event;
|
||||
|
||||
// 获取表格的所有数据和列配置
|
||||
const fullData = $table.getFullData();
|
||||
const columns = $table.getColumns();
|
||||
const currentColumnIndex = $table.getColumnIndex(currentColumn);
|
||||
|
||||
// ArrowUp - 向上移动一行
|
||||
if (key === "ArrowUp" && currentRowIndex > 0) {
|
||||
const toIndex = currentRowIndex - 1;
|
||||
$table.setEditRow(fullData[toIndex], currentColumn.property);
|
||||
$table.setCurrentRow(fullData[toIndex]);
|
||||
}
|
||||
// ArrowDown - 向下移动一行
|
||||
else if (key === "ArrowDown" && currentRowIndex < fullData.length - 1) {
|
||||
const toIndex = currentRowIndex + 1;
|
||||
$table.setEditRow(fullData[toIndex], currentColumn.property);
|
||||
$table.setCurrentRow(fullData[toIndex]);
|
||||
}
|
||||
// ArrowLeft - 向左移动一列
|
||||
else if (key === "ArrowLeft" && currentColumnIndex > 0) {
|
||||
const toIndex = currentColumnIndex - 1;
|
||||
$table.setEditCell(currentRow, columns[toIndex]);
|
||||
$table.setCurrentColumn(columns[toIndex]);
|
||||
}
|
||||
// ArrowRight - 向右移动一列
|
||||
else if (key === "ArrowRight" && currentColumnIndex < columns.length - 1) {
|
||||
const toIndex = currentColumnIndex + 1;
|
||||
$table.setEditCell(currentRow, columns[toIndex]);
|
||||
$table.setCurrentColumn(columns[toIndex]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,980 @@
|
||||
// import ssDialog from '@/components/ssDialog.vue'
|
||||
// import shDialog from '@/components/shDialog.vue'
|
||||
// import bhDialog from '@/components/bhDialog.vue'
|
||||
import toshDialog from "@/components/sendsh/toshDialog.vue";
|
||||
|
||||
import { createVNode, render, h } from "vue";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import axios from "@/utils/axios";
|
||||
import { getDataBySql } from "@/utils/doSql";
|
||||
import dayjs from "dayjs";
|
||||
import { useUserStore } from "@/store/user";
|
||||
|
||||
/**
|
||||
* 审核中心 - Vue3版本
|
||||
* @param {String} ywid - 业务ID
|
||||
* @param {String} savetable - 主表表名
|
||||
* @param {String} ModuleID - 模块ID
|
||||
* @param {String} state - 审核状态(如 审核通过、驳回)
|
||||
* @param {Array} shsetdatas - 审核流程设定
|
||||
* @param {Function} func - 回调函数
|
||||
*/
|
||||
export async function mod_shcenter_sh(ywid, savetable, ModuleID, state, shsetdatas, Fuserid, func) {
|
||||
try {
|
||||
// === 1. 读取业务主表数据 ===
|
||||
const mainSql = `select * from ${savetable} where b_id='${ywid}' order by b_id`;
|
||||
const mainRes = await axios.get("/selectlistbysql", { params: { sql: mainSql } });
|
||||
const ywdatas = mainRes.data?.data?.records || [];
|
||||
if (ywdatas.length === 0) {
|
||||
ElMessage.warning("当前业务单不存在");
|
||||
return;
|
||||
}
|
||||
|
||||
const rowdata = ywdatas[0];
|
||||
const ywownerid = rowdata.b_owner_id;
|
||||
|
||||
// === 2. 查询待审记录 ===
|
||||
const shSql = `select * from sh_record where b_dj_id='${ywid}' and b_module_id='${ModuleID}' order by b_id desc`;
|
||||
const shRes = await axios.get("/selectlistbysql", { params: { sql: shSql } });
|
||||
const shrecords = shRes.data?.data?.records || [];
|
||||
|
||||
if (shrecords.length === 0) {
|
||||
ElMessage.warning("没有待审记录");
|
||||
return;
|
||||
}
|
||||
|
||||
const now_level = Number(shrecords[0].b_level);
|
||||
const shlevel = now_level + 1;
|
||||
const dsh_useid = shrecords[0].b_tosh_useid;
|
||||
const userid = Fuserid; // 当前登录用户ID(请根据实际修改)
|
||||
|
||||
if (String(dsh_useid).trim() !== String(userid).trim()) {
|
||||
ElMessage.error("你没有该票业务的审批权限");
|
||||
return;
|
||||
}
|
||||
|
||||
// === 3. 判断审批权限、是否有下一步 ===
|
||||
let can_sh = false;
|
||||
let can_nextsh = false;
|
||||
let level_userid = [];
|
||||
|
||||
for (const shset of shsetdatas) {
|
||||
if (Number(shset.b_level) === Number(shlevel)) {
|
||||
if (shset.b_user_id === dsh_useid) {
|
||||
can_sh = true;
|
||||
}
|
||||
}
|
||||
if (Number(shset.b_level) === Number(shlevel + 1)) {
|
||||
can_nextsh = true;
|
||||
level_userid.push(shset.b_user_id);
|
||||
}
|
||||
}
|
||||
if (!can_sh) {
|
||||
ElMessage.error("你没有该票业务的审批权限");
|
||||
return;
|
||||
}
|
||||
|
||||
// === 4. 设置当前状态 ===
|
||||
const xxx = ["一", "二", "三", "四", "五", "六", "七", "八"];
|
||||
let sh_state = can_nextsh ? `${xxx[now_level]}审通过` : "审核通过";
|
||||
|
||||
const str_leveluserid = level_userid.map((item) => `'${item}'`).join(",");
|
||||
const searchcondition = `b_id in (${str_leveluserid})`;
|
||||
|
||||
const shSql1 = `select * from b_user where ${searchcondition}`;
|
||||
const shRes1 = await axios.get("/selectlistbysql", { params: { sql: shSql1 } });
|
||||
const shrecords_id = shRes1.data?.data?.records || [];
|
||||
|
||||
const level_userid_upadte = shrecords_id.map((item) => ({
|
||||
b_id: item.b_id,
|
||||
b_name: item.b_name,
|
||||
}));
|
||||
|
||||
// === 5. 弹出选择审批人弹窗 ===
|
||||
const data = await openShDialog(level_userid_upadte, ywownerid);
|
||||
if (!data) {
|
||||
ElMessage.info("已取消转送");
|
||||
return;
|
||||
}
|
||||
|
||||
// === 7. 调用保存函数 ===
|
||||
await save_sh_data(
|
||||
ModuleID,
|
||||
userid,
|
||||
savetable,
|
||||
rowdata,
|
||||
sh_state,
|
||||
shlevel,
|
||||
data.user,
|
||||
data.memo,
|
||||
func,
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
ElMessage.error("审批失败");
|
||||
}
|
||||
}
|
||||
// export function openShDialog(levelUserIds, ywownerid) {
|
||||
// return new Promise(resolve => {
|
||||
// const container = document.createElement('div')
|
||||
// document.body.appendChild(container)
|
||||
|
||||
// const closeDialog = () => {
|
||||
// render(null, container)
|
||||
// document.body.removeChild(container)
|
||||
// }
|
||||
|
||||
// const vnode = createVNode(shDialog, {
|
||||
// modelValue: true,
|
||||
// levelUserIds,
|
||||
// ywownerid,
|
||||
// onConfirm: data => {
|
||||
// closeDialog()
|
||||
// resolve(data)
|
||||
// },
|
||||
// onCancel: () => {
|
||||
// closeDialog()
|
||||
// resolve(null)
|
||||
// }
|
||||
// })
|
||||
|
||||
// render(vnode, container)
|
||||
// })
|
||||
// }
|
||||
|
||||
/**
|
||||
* 模拟保存审批数据
|
||||
*/
|
||||
async function save_sh_data(
|
||||
ModuleID,
|
||||
userid,
|
||||
savetable,
|
||||
rowdata,
|
||||
state,
|
||||
shlevel,
|
||||
tosh_useid,
|
||||
sh_memo,
|
||||
func,
|
||||
) {
|
||||
if (rowdata == undefined) return;
|
||||
|
||||
const updateRows = [];
|
||||
const insert_sh_records = [];
|
||||
|
||||
var oldstate = rowdata.b_state;
|
||||
const inputdatetime = dayjs().format("YYYY-MM-DD HH:mm:ss");
|
||||
|
||||
const obj = { b_id: rowdata.b_id, b_state: state };
|
||||
|
||||
updateRows.push(obj);
|
||||
|
||||
insert_sh_records.push({
|
||||
b_module_id: ModuleID,
|
||||
b_user_id: userid,
|
||||
b_level: shlevel,
|
||||
b_name: state,
|
||||
b_dj_id: rowdata.b_id,
|
||||
b_sh: "1",
|
||||
b_sh_date: inputdatetime,
|
||||
b_sh_memo: sh_memo,
|
||||
b_tosh_useid: tosh_useid,
|
||||
});
|
||||
|
||||
const requestData = [];
|
||||
if (updateRows.length > 0) {
|
||||
requestData.push({
|
||||
tableName: savetable,
|
||||
keyField: "b_id",
|
||||
inserts: [],
|
||||
updates: updateRows,
|
||||
deletes: [],
|
||||
});
|
||||
requestData.push({
|
||||
tableName: "sh_record",
|
||||
keyField: "b_id",
|
||||
inserts: insert_sh_records,
|
||||
updates: [],
|
||||
deletes: [],
|
||||
});
|
||||
|
||||
if (savetable === "cw_zdorder") {
|
||||
const updateFeeData = [];
|
||||
const zdidarr = updateRows.map((row) => `'${row.b_id}'`);
|
||||
|
||||
// 获取账单状态
|
||||
const getBStateById = (id) => {
|
||||
const row = updateRows.find((r) => r.b_id === id);
|
||||
return row ? row.b_state : "";
|
||||
};
|
||||
|
||||
// 这里替代 loaddatas()
|
||||
const searchsql = `isnull(mx_zdorderid, '') in (${zdidarr.join(",")})`;
|
||||
const cwres = await axios.get("/selectlistbysql", {
|
||||
params: {
|
||||
sql: `select * from bs_business_cw where ${searchsql} order by subid`,
|
||||
},
|
||||
});
|
||||
|
||||
const cwrows = cwres.data?.data?.records || [];
|
||||
|
||||
for (const cw of cwrows) {
|
||||
const zdstate = getBStateById(cw.mx_zdorderid) || state;
|
||||
updateFeeData.push({
|
||||
subid: cw.subid,
|
||||
father: cw.father,
|
||||
mx_zdorder_state: zdstate,
|
||||
});
|
||||
}
|
||||
|
||||
if (updateFeeData.length > 0) {
|
||||
requestData.push({
|
||||
tableName: "bs_business_cw",
|
||||
keyField: "subid",
|
||||
inserts: [],
|
||||
updates: updateFeeData,
|
||||
deletes: [],
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const response = await axios.post("/saveobjectV2", requestData, {
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
|
||||
if (response.data?.success) {
|
||||
ElMessage.success(state + "成功!");
|
||||
if (typeof func === "function") {
|
||||
await func();
|
||||
}
|
||||
} else {
|
||||
throw new Error(response.data?.message || "保存失败");
|
||||
}
|
||||
}
|
||||
|
||||
export const main_shcenter_ss = async (ywid, savetable, ModuleID, state, userid, func) => {
|
||||
// 1️⃣ 校验业务单是否存在
|
||||
let searchsql = `select * from ${savetable} where b_id='${ywid}' order by b_id`;
|
||||
const ywdatasRes = await axios.get("/selectlistbysql", { params: { sql: searchsql } });
|
||||
const ywdatas = ywdatasRes.data?.data?.records || [];
|
||||
if (!ywdatas.length) {
|
||||
ElMessage.error("当前业务单号不存在");
|
||||
return false;
|
||||
}
|
||||
|
||||
const newstate = ywdatas[0].b_state;
|
||||
const canuse_state = ["草拟", "审核驳回", ""];
|
||||
if (!canuse_state.includes(newstate)) {
|
||||
ElMessage.warning(`只有 ${canuse_state.join(",")} 的记录才能 ${state}!`);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2️⃣ 获取审批配置
|
||||
let sql = `select * from sh_b_set where b_module_id='${ModuleID}' order by b_level`;
|
||||
const shsetRes = await axios.get("/selectlistbysql", { params: { sql } });
|
||||
const shsetdatas = shsetRes.data?.data?.records || [];
|
||||
const level_userid = shsetdatas.filter((i) => i.b_level === "1").map((i) => i.b_user_id);
|
||||
|
||||
if (!level_userid.length) {
|
||||
ElMessage.error("当前模块未配置一级审批人");
|
||||
return false;
|
||||
}
|
||||
|
||||
const str_leveluserid = level_userid.map((item) => `'${item}'`).join(",");
|
||||
const searchcondition = `b_id in (${str_leveluserid})`;
|
||||
|
||||
const shSql1 = `select * from b_user where ${searchcondition}`;
|
||||
const shRes1 = await axios.get("/selectlistbysql", { params: { sql: shSql1 } });
|
||||
const shrecords_id = shRes1.data?.data?.records || [];
|
||||
|
||||
const level_userid_upadte = shrecords_id.map((item) => ({
|
||||
b_id: item.b_id,
|
||||
b_name: item.b_name,
|
||||
}));
|
||||
|
||||
// 3️⃣ 打开弹窗
|
||||
const selected = await openSelectApproverDialog(level_userid_upadte);
|
||||
if (!selected) {
|
||||
ElMessage.info("已取消送审");
|
||||
return;
|
||||
}
|
||||
// 4️⃣ 保存送审逻辑
|
||||
await save_ss_data(
|
||||
ModuleID,
|
||||
userid,
|
||||
savetable,
|
||||
ywid,
|
||||
newstate,
|
||||
state,
|
||||
selected.user,
|
||||
selected.memo,
|
||||
func,
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 动态创建审批人选择弹窗
|
||||
*/
|
||||
// function openSelectApproverDialog(levelUserIds) {
|
||||
// return new Promise(resolve => {
|
||||
// const container = document.createElement('div')
|
||||
// document.body.appendChild(container)
|
||||
|
||||
// const closeDialog = () => {
|
||||
// render(null, container)
|
||||
// document.body.removeChild(container)
|
||||
// }
|
||||
|
||||
// // 创建虚拟节点
|
||||
// const vnode = createVNode(ssDialog, {
|
||||
// levelUserIds,
|
||||
// modelValue: true, // 确保初始显示
|
||||
// 'onUpdate:visible': val => {
|
||||
// if (!val) closeDialog()
|
||||
// },
|
||||
// onConfirm: data => {
|
||||
// closeDialog()
|
||||
// resolve(data)
|
||||
// },
|
||||
// onCancel: () => {
|
||||
// closeDialog()
|
||||
// resolve(null)
|
||||
// },
|
||||
// })
|
||||
|
||||
// // 渲染到 DOM
|
||||
// render(vnode, container)
|
||||
// })
|
||||
// }
|
||||
/**
|
||||
* 保存送审数据(示例,可与你的后端对应)
|
||||
*/
|
||||
async function save_ss_data(
|
||||
ModuleID,
|
||||
userid,
|
||||
savetable,
|
||||
ywid,
|
||||
oldstate,
|
||||
state,
|
||||
tosh_useid,
|
||||
sh_memo,
|
||||
func,
|
||||
) {
|
||||
const updateRows = [];
|
||||
const insert_sh_records = [];
|
||||
const obj = { b_id: ywid, b_state: state };
|
||||
updateRows.push(obj);
|
||||
|
||||
const inputdatetime = dayjs().format("YYYY-MM-DD HH:mm:ss");
|
||||
|
||||
insert_sh_records.push({
|
||||
b_module_id: ModuleID,
|
||||
b_user_id: userid,
|
||||
b_level: "0",
|
||||
b_name: state,
|
||||
b_dj_id: ywid,
|
||||
b_sh: "1",
|
||||
b_sh_date: inputdatetime,
|
||||
b_sh_memo: sh_memo,
|
||||
b_tosh_useid: tosh_useid,
|
||||
});
|
||||
|
||||
const requestData = [];
|
||||
if (updateRows.length > 0) {
|
||||
requestData.push({
|
||||
tableName: savetable,
|
||||
keyField: "b_id",
|
||||
inserts: [],
|
||||
updates: updateRows,
|
||||
deletes: [],
|
||||
});
|
||||
requestData.push({
|
||||
tableName: "sh_record",
|
||||
keyField: "b_id",
|
||||
inserts: insert_sh_records,
|
||||
updates: [],
|
||||
deletes: [],
|
||||
});
|
||||
|
||||
if (savetable === "cw_zdorder") {
|
||||
const updateFeeData = [];
|
||||
const zdidarr = updateRows.map((row) => `'${row.b_id}'`);
|
||||
|
||||
// 获取账单状态
|
||||
const getBStateById = (id) => {
|
||||
const row = updateRows.find((r) => r.b_id === id);
|
||||
return row ? row.b_state : "";
|
||||
};
|
||||
|
||||
// 这里替代 loaddatas()
|
||||
const searchsql = `isnull(mx_zdorderid, '') in (${zdidarr.join(",")})`;
|
||||
const cwres = await axios.get("/selectlistbysql", {
|
||||
params: {
|
||||
sql: `select * from bs_business_cw where ${searchsql} order by subid`,
|
||||
},
|
||||
});
|
||||
|
||||
const cwrows = cwres.data?.data?.records || [];
|
||||
|
||||
for (const cw of cwrows) {
|
||||
const zdstate = getBStateById(cw.mx_zdorderid) || state;
|
||||
updateFeeData.push({
|
||||
subid: cw.subid,
|
||||
father: cw.father,
|
||||
mx_zdorder_state: zdstate,
|
||||
});
|
||||
}
|
||||
|
||||
if (updateFeeData.length > 0) {
|
||||
requestData.push({
|
||||
tableName: "bs_business_cw",
|
||||
keyField: "subid",
|
||||
inserts: [],
|
||||
updates: updateFeeData,
|
||||
deletes: [],
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const response = await axios.post("/saveobjectV2", requestData, {
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
|
||||
if (response.data?.success) {
|
||||
ElMessage.success(state + "成功!");
|
||||
if (typeof func === "function") {
|
||||
await func();
|
||||
}
|
||||
} else {
|
||||
throw new Error(response.data?.message || "保存失败");
|
||||
}
|
||||
}
|
||||
|
||||
export const mod_shcenter_bh = async (ywid, savetable, ModuleID, state, userid, func) => {
|
||||
// 加载业务数据
|
||||
let searchsql = `select * from ${savetable} where b_id='${ywid}' order by b_id`;
|
||||
const ywdatasRes = await axios.get("/selectlistbysql", { params: { sql: searchsql } });
|
||||
const ywdatas = ywdatasRes.data?.data?.records || [];
|
||||
if (!ywdatas.length) {
|
||||
ElMessage.error("当前业务单号不存在");
|
||||
return false;
|
||||
}
|
||||
|
||||
const rowdata = ywdatas[0];
|
||||
const ywownerid = rowdata.b_owner_id;
|
||||
const nowstate = rowdata.b_state;
|
||||
|
||||
if (nowstate === "审核驳回") {
|
||||
ElMessage.warning("已驳回!请检查!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 查询审核记录
|
||||
const shSql = `select * from sh_record where b_dj_id='${ywid}' and b_module_id='${ModuleID}' order by b_id desc`;
|
||||
const shRes = await axios.get("/selectlistbysql", { params: { sql: shSql } });
|
||||
const shrecords = shRes.data?.data?.records || [];
|
||||
|
||||
let now_level = 0;
|
||||
|
||||
if (!shrecords || shrecords.length === 0) {
|
||||
// 没有记录时判断权限
|
||||
const shSql1 = `select * from sh_b_set where b_module_id='${ModuleID}' and b_user_id='${userid}' order by b_level`;
|
||||
const shRes1 = await axios.get("/selectlistbysql", { params: { sql: shSql1 } });
|
||||
const shsetdatas = shRes1.data?.data?.records || [];
|
||||
if (!shsetdatas || shsetdatas.length === 0) {
|
||||
ElMessage.warning("你没有该票业务的驳回权限");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
now_level = shrecords[0].b_level;
|
||||
const dsh_useid = shrecords[0].b_tosh_useid;
|
||||
const sh_userid = shrecords[0].b_user_id;
|
||||
|
||||
if (dsh_useid !== userid && sh_userid !== userid && now_level > 0) {
|
||||
ElMessage.warning("你没有该票业务的驳回权限");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (nowstate === "送审" && dsh_useid !== userid) {
|
||||
ElMessage.warning("你没有该票业务的驳回权限");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// === 5. 弹出驳回弹窗 ===
|
||||
const data = await openBHDialog("", ywownerid);
|
||||
if (!data) {
|
||||
ElMessage.info("已取消驳回");
|
||||
return;
|
||||
}
|
||||
|
||||
await save_bh_data(
|
||||
ModuleID,
|
||||
userid,
|
||||
savetable,
|
||||
ywid,
|
||||
state,
|
||||
now_level,
|
||||
data.user,
|
||||
data.memo,
|
||||
func,
|
||||
);
|
||||
};
|
||||
// export function openBHDialog(levelUserIds, ywownerid) {
|
||||
// return new Promise(resolve => {
|
||||
// const container = document.createElement('div')
|
||||
// document.body.appendChild(container)
|
||||
|
||||
// const closeDialog = () => {
|
||||
// render(null, container)
|
||||
// document.body.removeChild(container)
|
||||
// }
|
||||
|
||||
// const vnode = createVNode(bhDialog, {
|
||||
// modelValue: true,
|
||||
// levelUserIds,
|
||||
// ywownerid,
|
||||
// onConfirm: data => {
|
||||
// closeDialog()
|
||||
// resolve(data)
|
||||
// },
|
||||
// onCancel: () => {
|
||||
// closeDialog()
|
||||
// resolve(null)
|
||||
// }
|
||||
// })
|
||||
|
||||
// render(vnode, container)
|
||||
// })
|
||||
// }
|
||||
|
||||
async function save_bh_data(
|
||||
ModuleID,
|
||||
userid,
|
||||
savetable,
|
||||
ywid,
|
||||
state,
|
||||
now_level,
|
||||
tosh_useid,
|
||||
sh_memo,
|
||||
func,
|
||||
) {
|
||||
const updateRows = [];
|
||||
const insert_sh_records = [];
|
||||
|
||||
const inputdatetime = dayjs().format("YYYY-MM-DD HH:mm:ss");
|
||||
|
||||
const obj = { b_id: ywid, b_state: state };
|
||||
|
||||
updateRows.push(obj);
|
||||
|
||||
insert_sh_records.push({
|
||||
b_module_id: ModuleID,
|
||||
b_user_id: userid,
|
||||
b_level: now_level,
|
||||
b_name: state,
|
||||
b_dj_id: ywid,
|
||||
b_sh: "0",
|
||||
b_sh_date: inputdatetime,
|
||||
b_sh_memo: sh_memo,
|
||||
b_tosh_useid: tosh_useid,
|
||||
});
|
||||
|
||||
const requestData = [];
|
||||
if (updateRows.length > 0) {
|
||||
requestData.push({
|
||||
tableName: savetable,
|
||||
keyField: "b_id",
|
||||
inserts: [],
|
||||
updates: updateRows,
|
||||
deletes: [],
|
||||
});
|
||||
requestData.push({
|
||||
tableName: "sh_record",
|
||||
keyField: "b_id",
|
||||
inserts: insert_sh_records,
|
||||
updates: [],
|
||||
deletes: [],
|
||||
});
|
||||
|
||||
if (savetable === "cw_zdorder") {
|
||||
const updateFeeData = [];
|
||||
const zdidarr = updateRows.map((row) => `'${row.b_id}'`);
|
||||
|
||||
// 获取账单状态
|
||||
const getBStateById = (id) => {
|
||||
const row = updateRows.find((r) => r.b_id === id);
|
||||
return row ? row.b_state : "";
|
||||
};
|
||||
|
||||
// 这里替代 loaddatas()
|
||||
const searchsql = `isnull(mx_zdorderid, '') in (${zdidarr.join(",")})`;
|
||||
const cwres = await axios.get("/selectlistbysql", {
|
||||
params: {
|
||||
sql: `select * from bs_business_cw where ${searchsql} order by subid`,
|
||||
},
|
||||
});
|
||||
|
||||
const cwrows = cwres.data?.data?.records || [];
|
||||
|
||||
for (const cw of cwrows) {
|
||||
const zdstate = getBStateById(cw.mx_zdorderid) || state;
|
||||
updateFeeData.push({
|
||||
subid: cw.subid,
|
||||
father: cw.father,
|
||||
mx_zdorder_state: zdstate,
|
||||
});
|
||||
}
|
||||
|
||||
if (updateFeeData.length > 0) {
|
||||
requestData.push({
|
||||
tableName: "bs_business_cw",
|
||||
keyField: "subid",
|
||||
inserts: [],
|
||||
updates: updateFeeData,
|
||||
deletes: [],
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const response = await axios.post("/saveobjectV2", requestData, {
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
|
||||
if (response.data?.success) {
|
||||
ElMessage.success(state + "成功!");
|
||||
if (typeof func === "function") {
|
||||
await func();
|
||||
}
|
||||
} else {
|
||||
throw new Error(response.data?.message || "保存失败");
|
||||
}
|
||||
}
|
||||
|
||||
export const modgrididstate = async (rows, savetable, ModuleID, state, func) => {
|
||||
if (!rows || rows.length === 0) {
|
||||
ElMessage.warning("请勾选要送审的记录!");
|
||||
return;
|
||||
}
|
||||
// 状态可变范围
|
||||
let canuse_state = [];
|
||||
if (state === "送审") canuse_state = ["草拟", "审核驳回", ""];
|
||||
if (state === "归档") canuse_state = ["审核通过", "完成"];
|
||||
// 时间辅助
|
||||
const inputdatetime = ["cw_zdorder", "cw_zdorder_f"].includes(ModuleID)
|
||||
? dayjs().format("YYYY-MM-DD HH:mm:ss")
|
||||
: "";
|
||||
|
||||
const updateFeeData = [];
|
||||
const updateRows = [];
|
||||
// 遍历勾选行
|
||||
for (const row of rows) {
|
||||
if (!row) return;
|
||||
const oldstate = row.b_state || row.b_State;
|
||||
|
||||
const allowUpdate = canuse_state.length === 0 || canuse_state.includes(oldstate);
|
||||
|
||||
if (!allowUpdate) {
|
||||
ElMessage.warning(`只有 [${canuse_state.join(",")}] 的记录才能 ${state}!`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 针对 cw_zdorder 模块的附表更新逻辑
|
||||
if (["cw_zdorder", "cw_zdorder_f"].includes(ModuleID)) {
|
||||
let searchsql = `select * from bs_business_cw where isnull(mx_zdorderid,'')='${row.b_id}' order by subid`;
|
||||
const response = await axios.get("/selectlistbysql", { params: { sql: searchsql } });
|
||||
if (response.data?.success) {
|
||||
const records = response.data.data.records || [];
|
||||
if (records.length > 0) {
|
||||
for (const cw of records) {
|
||||
updateFeeData.push({
|
||||
subid: cw.subid,
|
||||
father: cw.father,
|
||||
mx_zdorder_state: state,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
// 审核驳回时校验费用
|
||||
if (state === "审核驳回") {
|
||||
const sql = `select count(*) as cnt,sum(case when isnull(mx_invoiceid,'')<>'' or isnull(mx_sumamount,0)<>0 then 1 else 0 end) as un_cnt from bs_business_cw where mx_zdorderid='${row.b_id}'`;
|
||||
const response = await axios.get("/selectlistbysql", { params: { sql } });
|
||||
if (response.data?.success) {
|
||||
const records = response.data.data.records || [];
|
||||
if (records.length > 0) {
|
||||
if (records[0].cnt > 0 && records[0].cnt === records[0].un_cnt) {
|
||||
ElMessage.error("驳回失败!费用项已销账或开票!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 针对仓库模块的校验
|
||||
if (["ck_in", "ck_out"].includes(ModuleID)) {
|
||||
if (state === "审核驳回" && row.b_depotconfirm === "1") {
|
||||
ElMessage.error("驳回失败!仓库确认数据不能驳回!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const obj = { b_id: row.b_id, b_state: state };
|
||||
updateRows.push(obj);
|
||||
}
|
||||
const requestData = [];
|
||||
|
||||
if (updateRows.length > 0) {
|
||||
requestData.push({
|
||||
tableName: savetable,
|
||||
keyField: "b_id",
|
||||
inserts: [],
|
||||
updates: updateRows,
|
||||
deletes: [],
|
||||
});
|
||||
if (updateFeeData.length > 0) {
|
||||
requestData.push({
|
||||
tableName: "bs_business_cw",
|
||||
keyField: "subid",
|
||||
inserts: [],
|
||||
updates: updateFeeData,
|
||||
deletes: [],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const response = await axios.post("/saveobjectV2", requestData, {
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
|
||||
if (response.data?.success) {
|
||||
ElMessage.success(state + "成功!");
|
||||
if (typeof func === "function") {
|
||||
await func();
|
||||
}
|
||||
} else {
|
||||
throw new Error(response.data?.message || "保存失败");
|
||||
}
|
||||
};
|
||||
|
||||
// ---------------------------
|
||||
export async function tosh(row, moduleid, tablename, func) {
|
||||
try {
|
||||
if (row.b_state !== "草拟" && !row.b_state.includes("驳回")) {
|
||||
ElMessage.warning("只有状态为草拟或驳回的数据才能进行送审");
|
||||
return;
|
||||
}
|
||||
let strid = row.b_id;
|
||||
|
||||
// === 5. 弹出选择审批人弹窗 ===
|
||||
const data = await opentoshDialog();
|
||||
if (!data) {
|
||||
ElMessage.info("已取消送审");
|
||||
return;
|
||||
}
|
||||
|
||||
// === 7. 调用保存函数 ===
|
||||
await save_tosh_data(moduleid, tablename, strid, data.memo, func);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
ElMessage.error("送审失败");
|
||||
}
|
||||
}
|
||||
export function opentoshDialog(levelUserIds, ywownerid) {
|
||||
return new Promise((resolve) => {
|
||||
const container = document.createElement("div");
|
||||
document.body.appendChild(container);
|
||||
|
||||
const closeDialog = () => {
|
||||
render(null, container);
|
||||
document.body.removeChild(container);
|
||||
};
|
||||
|
||||
const vnode = createVNode(toshDialog, {
|
||||
modelValue: true,
|
||||
onConfirm: (data) => {
|
||||
closeDialog();
|
||||
resolve(data);
|
||||
},
|
||||
onCancel: () => {
|
||||
closeDialog();
|
||||
resolve(null);
|
||||
},
|
||||
});
|
||||
|
||||
render(vnode, container);
|
||||
});
|
||||
}
|
||||
async function save_tosh_data(ModuleID, tablename, strid, sh_memo, func) {
|
||||
const userStore = useUserStore();
|
||||
|
||||
let sstate = "";
|
||||
let jobj = [];
|
||||
let recordrows = [];
|
||||
let wxsenddatas = [];
|
||||
let thistime = dayjs().format("YYYY-MM-DD HH:mm:ss");
|
||||
|
||||
const res = await getDataBySql(`select * from ${tablename} where b_id='${strid}' order by b_id`);
|
||||
if (res.records.length > 0) {
|
||||
for (let item of res.records) {
|
||||
const res1 = await getDataBySql(`select b_state from ${tablename} where b_id='${item.b_id}'`);
|
||||
if (res1.records.length > 0) {
|
||||
sstate = res1.records[0].b_state;
|
||||
}
|
||||
|
||||
if (sstate != "草拟" && sstate.indexOf("驳回") <= -1) {
|
||||
ElMessage.warning("只有状态为草拟或驳回的数据才能进行送审");
|
||||
return;
|
||||
}
|
||||
|
||||
let jtmp = {};
|
||||
jtmp.b_id = item.b_id;
|
||||
jtmp.b_state = "送审";
|
||||
jobj.push(jtmp);
|
||||
|
||||
var recrow = {};
|
||||
recrow["b_module_id"] = ModuleID;
|
||||
recrow["b_user_id"] = userStore.userInfo.userid;
|
||||
recrow["b_dj_id"] = item.b_id;
|
||||
recrow["b_level"] = "0";
|
||||
recrow["b_sh"] = "1";
|
||||
recrow["b_name"] = "送审";
|
||||
recrow["b_sh_date"] = thistime;
|
||||
recrow["b_sh_memo"] = sh_memo;
|
||||
recordrows.push(recrow);
|
||||
|
||||
let modname = "";
|
||||
const res = await getDataBySql(`select b_ChineseName from s_module where b_id='${ModuleID}'`);
|
||||
if (res.records.length > 0) {
|
||||
modname = res.records[0].b_ChineseName;
|
||||
}
|
||||
|
||||
const ds_datas = await getDataBySql(
|
||||
`select sh_b_set.b_condition,b_user_id,b_user.b_phone,sh_b_set.b_level,b_user.b_password from sh_b_set left join b_user on sh_b_set.b_user_id = b_user.b_id where b_module_id='${ModuleID}' and b_level='1'`,
|
||||
);
|
||||
if (ds_datas.records.length > 0) {
|
||||
for (const k of ds_datas.records) {
|
||||
if (k.b_phone != "") {
|
||||
let canuse = true;
|
||||
let condition = k.b_condition;
|
||||
let mobileids = k.b_phone;
|
||||
if (condition) {
|
||||
const res1 = await getDataBySql(
|
||||
`select * from ${tablename} where b_id='${item.b_id}' and ${condition}`,
|
||||
);
|
||||
if (res1.records.length == 0) {
|
||||
canuse = false;
|
||||
}
|
||||
if (canuse) {
|
||||
var obj = {};
|
||||
obj["mobileids"] = mobileids;
|
||||
obj["b_id"] = item.b_id;
|
||||
obj["modid"] = modname;
|
||||
obj["b_owner_id"] = userStore.userInfo.userid;
|
||||
obj["orgid"] = userStore.userInfo.orgid;
|
||||
obj["userid"] = k.b_user_id;
|
||||
obj["password"] = k.b_password;
|
||||
wxsenddatas.push(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const requestData = [
|
||||
{
|
||||
tableName: "sh_record",
|
||||
keyField: "b_id",
|
||||
inserts: recordrows,
|
||||
updates: [],
|
||||
deletes: [],
|
||||
},
|
||||
{
|
||||
tableName: tablename,
|
||||
keyField: "b_id",
|
||||
inserts: [],
|
||||
updates: jobj,
|
||||
deletes: [],
|
||||
},
|
||||
];
|
||||
|
||||
const response = await axios.post("/saveobjectV2", requestData, {
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
|
||||
if (response.data?.success) {
|
||||
ElMessage.success("送审成功!");
|
||||
if (typeof func === "function") {
|
||||
await func();
|
||||
}
|
||||
} else {
|
||||
throw new Error(response.data?.message || "保存失败");
|
||||
}
|
||||
}
|
||||
export async function shcenter_cs(rows, ModuleID, tablename, func) {
|
||||
const userStore = useUserStore();
|
||||
|
||||
let sstate = "";
|
||||
let jobj = [];
|
||||
let recordrows = [];
|
||||
let thistime = dayjs().format("YYYY-MM-DD HH:mm:ss");
|
||||
|
||||
const res1 = await getDataBySql(`select b_state from ${tablename} where b_id='${rows.b_id}'`);
|
||||
if (res1.records.length > 0) {
|
||||
sstate = res1.records[0].b_state;
|
||||
}
|
||||
|
||||
if (sstate != "送审") {
|
||||
ElMessage.warning("只有状态为送审的数据才能进行撤审!");
|
||||
return;
|
||||
}
|
||||
|
||||
let jtmp = {};
|
||||
jtmp.b_id = rows.b_id;
|
||||
jtmp.b_state = "草拟";
|
||||
jobj.push(jtmp);
|
||||
|
||||
var recrow = {};
|
||||
recrow["b_module_id"] = ModuleID;
|
||||
recrow["b_user_id"] = userStore.userInfo.userid;
|
||||
recrow["b_dj_id"] = rows.b_id;
|
||||
recrow["b_level"] = "0";
|
||||
recrow["b_sh"] = "0";
|
||||
recrow["b_name"] = "撤销送审";
|
||||
recrow["b_sh_date"] = thistime;
|
||||
recrow["b_sh_memo"] = "";
|
||||
recordrows.push(recrow);
|
||||
|
||||
const requestData = [
|
||||
{
|
||||
tableName: "sh_record",
|
||||
keyField: "b_id",
|
||||
inserts: recordrows,
|
||||
updates: [],
|
||||
deletes: [],
|
||||
},
|
||||
{
|
||||
tableName: tablename,
|
||||
keyField: "b_id",
|
||||
inserts: [],
|
||||
updates: jobj,
|
||||
deletes: [],
|
||||
},
|
||||
];
|
||||
|
||||
const response = await axios.post("/saveobjectV2", requestData, {
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
|
||||
if (response.data?.success) {
|
||||
ElMessage.success("撤审成功!");
|
||||
if (typeof func === "function") {
|
||||
await func();
|
||||
}
|
||||
} else {
|
||||
throw new Error(response.data?.message || "保存失败");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
* 高精度数学工具。
|
||||
*
|
||||
* 注意:
|
||||
* - add / subtract / multiply / divide 返回的是 Big 包装对象,不是普通 number/string。
|
||||
* - 需要写入表单、展示到页面或提交字符串金额时,必须调用 `.toFixed()` 转成字符串。
|
||||
* - 空值、null、undefined、非法数字会按 0 处理。
|
||||
*
|
||||
* 示例:
|
||||
* math.multiply(price, qty).toFixed()
|
||||
* math.divide(amount, rate).toFixed(4)
|
||||
*/
|
||||
import Big from "big.js";
|
||||
|
||||
let defaultDecimal = 2;
|
||||
|
||||
function getDecimal(decimal = defaultDecimal) {
|
||||
const value = Number(decimal);
|
||||
return Number.isInteger(value) && value >= 0 ? value : defaultDecimal;
|
||||
}
|
||||
|
||||
class MathBig extends Big {
|
||||
toFixed(decimal = defaultDecimal) {
|
||||
return super.toFixed(getDecimal(decimal));
|
||||
}
|
||||
}
|
||||
|
||||
function toBig(value) {
|
||||
try {
|
||||
if (value == null || value === "") return new Big(0);
|
||||
|
||||
if (value instanceof Big) return value;
|
||||
|
||||
return new Big(String(value).trim());
|
||||
} catch {
|
||||
return new Big(0);
|
||||
}
|
||||
}
|
||||
|
||||
function wrap(value) {
|
||||
return new MathBig(value);
|
||||
}
|
||||
|
||||
const math = {
|
||||
/**
|
||||
* 设置默认小数位数。
|
||||
* @param {number|string} decimal 默认保留的小数位数,非法值会回退为当前默认值。
|
||||
* @returns {typeof math} 返回 math,方便链式调用。
|
||||
*/
|
||||
setDecimal(decimal) {
|
||||
defaultDecimal = getDecimal(decimal);
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* 加法。
|
||||
* @param {...(number|string|Big|null|undefined)} values 需要相加的值,支持多个参数。
|
||||
* @returns {MathBig} 高精度结果;转为字符串必须调用 `.toFixed()`。
|
||||
*/
|
||||
add(...values) {
|
||||
return wrap(values.reduce((total, value) => total.plus(toBig(value)), new Big(0)));
|
||||
},
|
||||
|
||||
/**
|
||||
* 减法。
|
||||
* @param {number|string|Big|null|undefined} firstValue 被减数。
|
||||
* @param {...(number|string|Big|null|undefined)} values 减数,支持多个参数。
|
||||
* @returns {MathBig} 高精度结果;转为字符串必须调用 `.toFixed()`。
|
||||
*/
|
||||
subtract(firstValue, ...values) {
|
||||
return wrap(values.reduce((total, value) => total.minus(toBig(value)), toBig(firstValue)));
|
||||
},
|
||||
|
||||
/**
|
||||
* 乘法。
|
||||
* @param {...(number|string|Big|null|undefined)} values 需要相乘的值,支持多个参数。
|
||||
* @returns {MathBig} 高精度结果;转为字符串必须调用 `.toFixed()`。
|
||||
*/
|
||||
multiply(...values) {
|
||||
return wrap(values.reduce((total, value) => total.times(toBig(value)), new Big(1)));
|
||||
},
|
||||
|
||||
/**
|
||||
* 除法。
|
||||
* @param {number|string|Big|null|undefined} firstValue 被除数。
|
||||
* @param {...(number|string|Big|null|undefined)} values 除数,支持多个参数;除数为 0 时本次结果返回 0。
|
||||
* @returns {MathBig} 高精度结果;转为字符串必须调用 `.toFixed()`。
|
||||
*/
|
||||
divide(firstValue, ...values) {
|
||||
return wrap(
|
||||
values.reduce((total, value) => {
|
||||
const divisor = toBig(value);
|
||||
return divisor.eq(0) ? new Big(0) : total.div(divisor);
|
||||
}, toBig(firstValue)),
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* 将任意数值按指定小数位转成字符串。
|
||||
* @param {number|string|Big|null|undefined} value 需要格式化的值。
|
||||
* @param {number|string} [decimal] 小数位数;不传则使用默认小数位。
|
||||
* @returns {string} 格式化后的字符串。
|
||||
*/
|
||||
toFixed(value, decimal) {
|
||||
return toBig(value).toFixed(decimal);
|
||||
},
|
||||
};
|
||||
|
||||
export default math;
|
||||
@@ -0,0 +1,31 @@
|
||||
// permission.js
|
||||
import { useUserStore } from "../store/user";
|
||||
|
||||
export default {
|
||||
install(app) {
|
||||
function updatePermission(el, permissionId) {
|
||||
const userStore = useUserStore();
|
||||
const disabled = !userStore.hasActionPermission(permissionId);
|
||||
|
||||
// 原生支持 disabled 的元素
|
||||
if ("disabled" in el) {
|
||||
el.disabled = disabled;
|
||||
}
|
||||
|
||||
// 通用处理
|
||||
el.style.pointerEvents = disabled ? "none" : "";
|
||||
el.style.opacity = disabled ? "0.6" : "";
|
||||
el.setAttribute("aria-disabled", disabled ? "true" : "false");
|
||||
}
|
||||
|
||||
app.directive("permission", {
|
||||
mounted(el, binding) {
|
||||
updatePermission(el, binding.value);
|
||||
},
|
||||
|
||||
updated(el, binding) {
|
||||
updatePermission(el, binding.value);
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,64 @@
|
||||
import dayjs from "dayjs";
|
||||
|
||||
export function formatToDate(date) {
|
||||
const validDate = dayjs(date);
|
||||
if (!validDate.isValid()) {
|
||||
return date;
|
||||
}
|
||||
return validDate.format("YYYY-MM-DD");
|
||||
}
|
||||
|
||||
export function formatToDateTime(date) {
|
||||
const validDate = dayjs(date);
|
||||
if (!validDate.isValid()) {
|
||||
return date;
|
||||
}
|
||||
return validDate.format("YYYY-MM-DD HH:mm:ss");
|
||||
}
|
||||
|
||||
export function getDateTime() {
|
||||
return dayjs().format("YYYY-MM-DD HH:mm:ss");
|
||||
}
|
||||
|
||||
export function getDate() {
|
||||
return dayjs().format("YYYY-MM-DD");
|
||||
}
|
||||
|
||||
export function upperCase(str) {
|
||||
if (typeof str === "string") {
|
||||
return str.toUpperCase();
|
||||
}
|
||||
|
||||
if (str != null && typeof str.toString === "function") {
|
||||
return str.toString().toUpperCase();
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
export function getcheckdjid(strvalid = "") {
|
||||
if (strvalid == undefined) {
|
||||
strvalid = "";
|
||||
}
|
||||
let tmpid = "";
|
||||
let djarr = strvalid.split("");
|
||||
// var x=/^[a-zA-Z0-9\u4e00-\u9fa5-_]+$/i;
|
||||
let sfuhao = '\/*:?<>"|&';
|
||||
for (let j in djarr) {
|
||||
let tmp = djarr[j];
|
||||
if (!sfuhao.includes(tmp)) {
|
||||
tmpid = tmpid + tmp;
|
||||
} else {
|
||||
tmpid = `${tmpid} `;
|
||||
}
|
||||
}
|
||||
return tmpid;
|
||||
}
|
||||
// 默认导出所有方法
|
||||
export default {
|
||||
getDate,
|
||||
getDateTime,
|
||||
upperCase,
|
||||
formatToDate,
|
||||
formatToDateTime,
|
||||
getcheckdjid,
|
||||
};
|
||||
Reference in new issue
Block a user