20260808172946
This commit is contained in:
1 parent
4fbfea82f2
commit
d72ca4193d
293 files changed
+37523
-73467
No files matched your search
@@ -1,11 +1,13 @@
|
||||
// src/utils/axios.js
|
||||
import axios from "axios";
|
||||
import { useUserStore } from "@/store";
|
||||
import { ElMessage } from "element-plus";
|
||||
import router from "@/router";
|
||||
|
||||
const instance = axios.create({
|
||||
//baseURL: "http://localhost:8089/api", // 后端接口地址
|
||||
baseURL: 'http://192.168.1.177:8089/api', // 后端接口地址
|
||||
// baseURL: "http://192.168.1.137:8089/api",
|
||||
baseURL: "http://localhost:8089/api", // 后端接口地址
|
||||
// baseURL: "http://192.168.1.137:8089/api", // 后端接口地址
|
||||
// baseURL: "http://192.168.1.177:8089/api",
|
||||
// baseURL: '/api', // 后端接口地址
|
||||
timeout: 30000,
|
||||
});
|
||||
@@ -15,7 +17,7 @@ instance.interceptors.request.use(
|
||||
(config) => {
|
||||
const userStore = useUserStore();
|
||||
if (userStore.isLogined()) {
|
||||
config.headers.Authorization = `Bearer ${userStore.userInfo.token}`;
|
||||
config.headers.Authorization = `Bearer ${userStore.getToken()}`;
|
||||
}
|
||||
return config;
|
||||
},
|
||||
@@ -26,6 +28,12 @@ instance.interceptors.request.use(
|
||||
instance.interceptors.response.use(
|
||||
(response) => response,
|
||||
(error) => {
|
||||
if (error.response && error.response.status === 401) {
|
||||
const userStore = useUserStore();
|
||||
userStore.reset();
|
||||
ElMessage.warning("登录过期,请重新登录");
|
||||
router.push("/login");
|
||||
}
|
||||
return Promise.reject(error);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Big from "big.js";
|
||||
import { formatToDate } from "./time";
|
||||
import { formatToDate, formatToDateTime } from "./time";
|
||||
|
||||
/**
|
||||
* 根据 format 判断列对齐方式
|
||||
@@ -45,8 +45,10 @@ export function formatValueByFormat(value, format) {
|
||||
minimumFractionDigits: decimals,
|
||||
maximumFractionDigits: decimals,
|
||||
}).format(num);
|
||||
} else if (fmt.startsWith("date")) {
|
||||
} else if (fmt === "date") {
|
||||
return formatToDate(value);
|
||||
} else if (fmt === "datetime") {
|
||||
return formatToDateTime(value);
|
||||
} else if (fmt.startsWith("number")) {
|
||||
return Number(value) || 0;
|
||||
}
|
||||
@@ -75,8 +77,10 @@ export function formatValueByFullFormat(value, format) {
|
||||
if (Number.isNaN(num)) return value;
|
||||
|
||||
return num.toFixed(decimals);
|
||||
} else if (fmt.startsWith("date")) {
|
||||
} else if (fmt === "date") {
|
||||
return formatToDate(value);
|
||||
} else if (fmt === "datetime") {
|
||||
return formatToDateTime(value);
|
||||
} else if (fmt.startsWith("number")) {
|
||||
return Number(value) || 0;
|
||||
}
|
||||
|
||||
@@ -378,6 +378,66 @@ export function diffData(
|
||||
) {
|
||||
const ignoreSet = new Set(ignoreFields);
|
||||
|
||||
const versionFields = new Set(["b_version", "mx_version"]);
|
||||
|
||||
|
||||
/**
|
||||
* 判断是否为数字类型
|
||||
*
|
||||
* 支持:
|
||||
* 40
|
||||
* "40"
|
||||
* "40.00"
|
||||
*/
|
||||
const isNumberValue = (value) => {
|
||||
if (typeof value === "number") {
|
||||
return !Number.isNaN(value);
|
||||
}
|
||||
|
||||
if (typeof value === "string") {
|
||||
if (value.trim() === "") {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !Number.isNaN(Number(value));
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 数据值比较
|
||||
*
|
||||
* 数字:
|
||||
* 40 === "40.00"
|
||||
*
|
||||
* 非数字:
|
||||
* 保持原 JSON 比较逻辑
|
||||
*/
|
||||
const isEqualValue = (a, b) => {
|
||||
|
||||
// null undefined 空字符串统一
|
||||
if (a == null || a === "") {
|
||||
a = "";
|
||||
}
|
||||
|
||||
if (b == null || b === "") {
|
||||
b = "";
|
||||
}
|
||||
|
||||
|
||||
// 两边都是数字,按数值比较
|
||||
if (isNumberValue(a) && isNumberValue(b)) {
|
||||
return Math.abs(Number(a) - Number(b)) < 0.000001;
|
||||
}
|
||||
|
||||
|
||||
// 其他类型保持原来的比较方式
|
||||
return JSON.stringify(a) === JSON.stringify(b);
|
||||
};
|
||||
|
||||
|
||||
const result = {
|
||||
hasChanges: false,
|
||||
insertdata: [],
|
||||
@@ -385,106 +445,239 @@ export function diffData(
|
||||
deletedata: [],
|
||||
};
|
||||
|
||||
// 过滤字段
|
||||
|
||||
const filterFields = (row) => {
|
||||
return Object.fromEntries(
|
||||
Object.entries(row).filter(([key]) => {
|
||||
return !key.startsWith("_") && !key.startsWith("v_") && !ignoreSet.has(key);
|
||||
return (
|
||||
!key.startsWith("_") &&
|
||||
!key.startsWith("v_") &&
|
||||
!ignoreSet.has(key)
|
||||
);
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
// 获取版本字段
|
||||
const getVersionData = (row) => {
|
||||
const data = {};
|
||||
|
||||
Object.keys(row).forEach((key) => {
|
||||
if (versionFields.has(key)) {
|
||||
data[key] = row[key];
|
||||
}
|
||||
});
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
|
||||
// ===========================
|
||||
// 单表处理
|
||||
// 单表
|
||||
// ===========================
|
||||
if (isSingle) {
|
||||
const isNewRecord = !original || Object.keys(original).length === 0 || !original[primaryKey];
|
||||
|
||||
// 新增
|
||||
const isNewRecord =
|
||||
!original ||
|
||||
Object.keys(original).length === 0 ||
|
||||
!original[primaryKey];
|
||||
|
||||
|
||||
if (isNewRecord) {
|
||||
|
||||
result.hasChanges = true;
|
||||
|
||||
result.insertdata.push(filterFields(current));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 修改
|
||||
|
||||
const changes = {};
|
||||
|
||||
|
||||
Object.keys(current).forEach((key) => {
|
||||
if (key.startsWith("_") || key.startsWith("v_") || ignoreSet.has(key)) return;
|
||||
|
||||
// 版本字段不参与比较
|
||||
if (versionFields.has(key)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (
|
||||
key.startsWith("_") ||
|
||||
key.startsWith("v_") ||
|
||||
ignoreSet.has(key)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const cur = current[key] ?? "";
|
||||
const org = original[key] ?? "";
|
||||
|
||||
if (JSON.stringify(cur) !== JSON.stringify(org)) {
|
||||
|
||||
if (!isEqualValue(cur, org)) {
|
||||
changes[key] = cur;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
if (Object.keys(changes).length > 0) {
|
||||
|
||||
result.hasChanges = true;
|
||||
|
||||
|
||||
result.updatedata.push({
|
||||
|
||||
[primaryKey]: current[primaryKey],
|
||||
|
||||
// 修改字段
|
||||
...changes,
|
||||
|
||||
// 版本
|
||||
...getVersionData(current),
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// ===========================
|
||||
// 子表处理
|
||||
// ===========================
|
||||
const pk = Array.isArray(primaryKey) ? primaryKey[0] : primaryKey;
|
||||
|
||||
const originalMap = new Map(original.map((item) => [item[pk], item]));
|
||||
|
||||
// ===========================
|
||||
// 子表
|
||||
// ===========================
|
||||
|
||||
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]))
|
||||
|
||||
.filter(
|
||||
(row) =>
|
||||
!row[pk] ||
|
||||
!originalMap.has(row[pk]),
|
||||
)
|
||||
|
||||
.map(filterFields);
|
||||
|
||||
|
||||
|
||||
// 修改
|
||||
|
||||
current.forEach((row) => {
|
||||
|
||||
const id = row[pk];
|
||||
|
||||
if (!id) return;
|
||||
|
||||
if (!id) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const oldRow = originalMap.get(id);
|
||||
|
||||
if (!oldRow) return;
|
||||
|
||||
if (!oldRow) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const changes = {};
|
||||
|
||||
|
||||
Object.keys(row).forEach((key) => {
|
||||
if (key === pk || key.startsWith("_") || key.startsWith("v_") || ignoreSet.has(key)) {
|
||||
|
||||
|
||||
// 版本字段不比较
|
||||
if (versionFields.has(key)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (
|
||||
key === pk ||
|
||||
key.startsWith("_") ||
|
||||
key.startsWith("v_") ||
|
||||
ignoreSet.has(key)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const cur = row[key] ?? "";
|
||||
const org = oldRow[key] ?? "";
|
||||
|
||||
if (JSON.stringify(cur) !== JSON.stringify(org)) {
|
||||
|
||||
if (!isEqualValue(cur, org)) {
|
||||
changes[key] = cur;
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
if (Object.keys(changes).length > 0) {
|
||||
|
||||
|
||||
result.updatedata.push({
|
||||
|
||||
[pk]: id,
|
||||
|
||||
...changes,
|
||||
|
||||
// 版本
|
||||
...getVersionData(row),
|
||||
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
// 删除
|
||||
|
||||
result.deletedata = original
|
||||
.filter((o) => !current.some((c) => c[pk] === o[pk]))
|
||||
|
||||
.filter(
|
||||
(o) =>
|
||||
!current.some(
|
||||
(c) => c[pk] === o[pk],
|
||||
),
|
||||
)
|
||||
|
||||
.map((o) => ({
|
||||
[pk]: o[pk],
|
||||
// 删除带版本
|
||||
...getVersionData(o),
|
||||
}));
|
||||
|
||||
|
||||
result.hasChanges =
|
||||
result.insertdata.length > 0 || result.updatedata.length > 0 || result.deletedata.length > 0;
|
||||
result.insertdata.length > 0 ||
|
||||
result.updatedata.length > 0 ||
|
||||
result.deletedata.length > 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -497,4 +690,4 @@ export default {
|
||||
fillDefaultArray,
|
||||
diffData,
|
||||
fillSerialNoAndDefaults,
|
||||
};
|
||||
};
|
||||
@@ -7,6 +7,10 @@ const error = ref(null);
|
||||
|
||||
export async function delBefore(moduleId, id) {
|
||||
try {
|
||||
if (!id) {
|
||||
return { success: true, message: "" };
|
||||
}
|
||||
|
||||
saving.value = true;
|
||||
error.value = "";
|
||||
|
||||
@@ -27,21 +31,25 @@ export async function delBefore(moduleId, id) {
|
||||
saving.value = false;
|
||||
}
|
||||
}
|
||||
export async function confirmDelete(rows) {
|
||||
export async function confirmDelete(rows, title = "移除") {
|
||||
const count = rows.length;
|
||||
|
||||
let msg = "确定要删除吗?";
|
||||
let msg = "确定要" + title + "吗?";
|
||||
if (count == 1) {
|
||||
let id = rows[0].b_id || rows[0].subid || "";
|
||||
msg = "确定要删除 " + id + " 吗?";
|
||||
msg = "确定要" + title + id + " 吗?";
|
||||
}
|
||||
|
||||
try {
|
||||
await ElMessageBox.confirm(count > 1 ? `确定要删除选中的 ${count} 条数据吗?` : msg, "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning",
|
||||
});
|
||||
await ElMessageBox.confirm(
|
||||
count > 1 ? `确定要${title}选中的 ${count} 条数据吗?` : msg,
|
||||
"提示",
|
||||
{
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning",
|
||||
},
|
||||
);
|
||||
return true;
|
||||
} catch (e) {
|
||||
if (e === "cancel" || e === "close") {
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
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);
|
||||
if (!sql || !sql.trim()) {
|
||||
console.warn("SQL不能为空");
|
||||
return [];
|
||||
}
|
||||
|
||||
const { data } = await axios.post("/selectlistbysql", {
|
||||
sql: sql.trim(),
|
||||
});
|
||||
|
||||
if (!data?.success) {
|
||||
throw new Error(data?.message || "查询失败");
|
||||
}
|
||||
|
||||
return data.data || [];
|
||||
}
|
||||
|
||||
export async function getDataBySqlPage(sql, pkColumn, page, size) {
|
||||
@@ -95,10 +95,8 @@ export async function loaddataApi(viewname, searchcondition) {
|
||||
}
|
||||
|
||||
export async function loaddatabysqlApi(sql) {
|
||||
const { data } = await axios.get("/selectlistbysql", {
|
||||
params: {
|
||||
sql,
|
||||
},
|
||||
const { data } = await axios.post("/selectlistbysql", {
|
||||
sql: sql.trim(),
|
||||
});
|
||||
|
||||
if (!data?.success) {
|
||||
@@ -120,6 +118,32 @@ export async function saveobjtApi(rows) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
export async function saveobjtV5Api(rows) {
|
||||
const { data } = await axios.post("/saveobjectV5", rows, {
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
|
||||
if (!data?.success) {
|
||||
throw new Error(data?.message || "保存失败");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
export async function saveobjtlockApi(rows) {
|
||||
const { data } = await axios.post("/saveobject_Lock", rows, {
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
|
||||
if (!data?.success) {
|
||||
throw new Error(data?.message || "保存失败");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
export async function getobjectApi(tablename, pkcolumn, pkvalue) {
|
||||
const params = {
|
||||
tableName: tablename,
|
||||
|
||||
@@ -637,21 +637,48 @@ export async function handleMappingConfig(selectId, subidliststr, targetRef) {
|
||||
}
|
||||
}
|
||||
|
||||
function escapeRegExp(str) {
|
||||
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||||
}
|
||||
export async function handleMappingConfigObj(selectId, subidliststr, targetRef) {
|
||||
let selectSql = "";
|
||||
|
||||
export const editableStates = ["草拟", "审核驳回", "送审"];
|
||||
// 是否可编辑
|
||||
export function isEditableState(state) {
|
||||
return editableStates.includes(state || "");
|
||||
}
|
||||
const data_selectsql = await getDataBySql(
|
||||
`select * from s_selectsql where selectid='${selectId}'`,
|
||||
);
|
||||
|
||||
// 审核通过状态
|
||||
export const approvedStates = ["审核通过"];
|
||||
// 是否审核通过
|
||||
export function isApprovedState(state) {
|
||||
return !approvedStates.includes(state || "");
|
||||
if (data_selectsql.records.length > 0) {
|
||||
selectSql = data_selectsql.records[0].selectsql;
|
||||
}
|
||||
|
||||
const sql = `${selectSql} ${subidliststr}`;
|
||||
|
||||
console.log("sql=----------");
|
||||
console.log(sql);
|
||||
|
||||
const data = await getDataBySql(sql);
|
||||
|
||||
if (!data.records.length) {
|
||||
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 row = data.records[0];
|
||||
|
||||
const resultObj = {};
|
||||
|
||||
maps.forEach((item) => {
|
||||
resultObj[item.des_field] = row[item.source_field];
|
||||
});
|
||||
|
||||
targetRef.value = {
|
||||
...targetRef.value,
|
||||
...JSON.parse(JSON.stringify(resultObj)),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
@@ -670,8 +697,6 @@ export default {
|
||||
handleSaveColumnEdit,
|
||||
getTableLabelEdit,
|
||||
handleMappingConfig,
|
||||
isEditableState,
|
||||
isApprovedState,
|
||||
};
|
||||
|
||||
// 导出单例
|
||||
@@ -0,0 +1,146 @@
|
||||
// src/formula/DependencyGraph.js
|
||||
|
||||
import extractVariables from "./VariableExtractor"
|
||||
|
||||
export default class DependencyGraph {
|
||||
|
||||
constructor(configs = []) {
|
||||
|
||||
/**
|
||||
* qty
|
||||
* ↓
|
||||
* amount
|
||||
* ↓
|
||||
* tax
|
||||
*/
|
||||
this.graph = new Map()
|
||||
|
||||
/**
|
||||
* amount
|
||||
* ↓
|
||||
* [qty,price]
|
||||
*/
|
||||
this.reverseGraph = new Map()
|
||||
|
||||
this.build(configs)
|
||||
|
||||
}
|
||||
|
||||
//---------------------------------------------
|
||||
// 建立依赖图
|
||||
//---------------------------------------------
|
||||
|
||||
build(configs) {
|
||||
|
||||
configs.forEach(item => {
|
||||
|
||||
if (!item.formula)
|
||||
return
|
||||
|
||||
const vars = extractVariables(item.formula)
|
||||
|
||||
//-----------------------------------------
|
||||
// 保存反向依赖
|
||||
//-----------------------------------------
|
||||
|
||||
this.reverseGraph.set(
|
||||
|
||||
item.field,
|
||||
|
||||
vars
|
||||
|
||||
)
|
||||
|
||||
//-----------------------------------------
|
||||
// 正向依赖
|
||||
//-----------------------------------------
|
||||
|
||||
vars.forEach(v => {
|
||||
|
||||
if (!this.graph.has(v))
|
||||
|
||||
this.graph.set(v, [])
|
||||
|
||||
this.graph.get(v).push(
|
||||
|
||||
item.field
|
||||
|
||||
)
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
//---------------------------------------------
|
||||
// 获取直接依赖
|
||||
//---------------------------------------------
|
||||
|
||||
getNext(field) {
|
||||
|
||||
return this.graph.get(field) || []
|
||||
|
||||
}
|
||||
|
||||
//---------------------------------------------
|
||||
// 获取公式依赖字段
|
||||
//---------------------------------------------
|
||||
|
||||
getVariables(field) {
|
||||
|
||||
return this.reverseGraph.get(field) || []
|
||||
|
||||
}
|
||||
|
||||
hasCycle() {
|
||||
|
||||
const visited = new Set()
|
||||
|
||||
const stack = new Set()
|
||||
|
||||
const dfs = (node) => {
|
||||
|
||||
if (stack.has(node))
|
||||
|
||||
return true
|
||||
|
||||
if (visited.has(node))
|
||||
|
||||
return false
|
||||
|
||||
visited.add(node)
|
||||
|
||||
stack.add(node)
|
||||
|
||||
const next =
|
||||
|
||||
this.getNext(node)
|
||||
|
||||
for (const n of next) {
|
||||
|
||||
if (dfs(n))
|
||||
|
||||
return true
|
||||
|
||||
}
|
||||
|
||||
stack.delete(node)
|
||||
|
||||
return false
|
||||
|
||||
}
|
||||
|
||||
for (const key of this.graph.keys()) {
|
||||
|
||||
if (dfs(key))
|
||||
|
||||
return true
|
||||
|
||||
}
|
||||
|
||||
return false
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
// src/formula/FormulaCache.js
|
||||
|
||||
/**
|
||||
* 编译缓存
|
||||
*/
|
||||
|
||||
class FormulaCache {
|
||||
|
||||
constructor() {
|
||||
|
||||
this.cache = new Map()
|
||||
|
||||
}
|
||||
|
||||
has(key) {
|
||||
|
||||
return this.cache.has(key)
|
||||
|
||||
}
|
||||
|
||||
get(key) {
|
||||
|
||||
return this.cache.get(key)
|
||||
|
||||
}
|
||||
|
||||
set(key, value) {
|
||||
|
||||
this.cache.set(key, value)
|
||||
|
||||
}
|
||||
|
||||
clear() {
|
||||
|
||||
this.cache.clear()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default new FormulaCache()
|
||||
@@ -0,0 +1,84 @@
|
||||
// src/formula/FormulaCompiler.js
|
||||
|
||||
import FormulaFunctions from "./FormulaFunctions"
|
||||
import FormulaCache from "./FormulaCache"
|
||||
|
||||
/**
|
||||
* 编译公式
|
||||
*
|
||||
* qty*price
|
||||
*
|
||||
* =>
|
||||
*
|
||||
* function(scope){}
|
||||
*/
|
||||
|
||||
export default class FormulaCompiler {
|
||||
|
||||
/**
|
||||
* 编译
|
||||
*/
|
||||
static compile(formula) {
|
||||
|
||||
if (!formula)
|
||||
return () => null
|
||||
|
||||
//---------------------------------
|
||||
// 已编译
|
||||
//---------------------------------
|
||||
|
||||
if (FormulaCache.has(formula)) {
|
||||
|
||||
return FormulaCache.get(formula)
|
||||
|
||||
}
|
||||
|
||||
//---------------------------------
|
||||
// 编译
|
||||
//---------------------------------
|
||||
|
||||
const fn = new Function(
|
||||
|
||||
"scope",
|
||||
|
||||
"func",
|
||||
|
||||
`
|
||||
with(func){
|
||||
with(scope){
|
||||
return ${formula}
|
||||
}
|
||||
}
|
||||
`
|
||||
)
|
||||
|
||||
//---------------------------------
|
||||
// 包装
|
||||
//---------------------------------
|
||||
|
||||
const execute = (scope) => {
|
||||
|
||||
try {
|
||||
|
||||
return fn(scope, FormulaFunctions)
|
||||
|
||||
}
|
||||
catch (e) {
|
||||
|
||||
console.error("公式执行失败:", formula)
|
||||
|
||||
console.error(e)
|
||||
|
||||
return null
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
FormulaCache.set(formula, execute)
|
||||
|
||||
return execute
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
// src/formula/FormulaEngine.js
|
||||
|
||||
import FormulaCompiler from "./FormulaCompiler";
|
||||
import DependencyGraph from "./DependencyGraph";
|
||||
import TableCalculator from "./TableCalculator";
|
||||
|
||||
export default class FormulaEngine {
|
||||
|
||||
constructor(configs = []) {
|
||||
|
||||
this.configs = configs;
|
||||
|
||||
// 行公式
|
||||
this.rowConfigs = [];
|
||||
|
||||
// 汇总公式
|
||||
this.tableConfigs = [];
|
||||
|
||||
// field -> config
|
||||
this.rowMap = new Map();
|
||||
|
||||
// DependencyGraph
|
||||
this.graph = null;
|
||||
|
||||
this.init();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
init() {
|
||||
|
||||
//-----------------------------
|
||||
// Row Formula
|
||||
//-----------------------------
|
||||
|
||||
this.rowConfigs = this.configs.filter(
|
||||
x => x.type === "row"
|
||||
);
|
||||
|
||||
//-----------------------------
|
||||
// Table Formula
|
||||
//-----------------------------
|
||||
|
||||
this.tableConfigs = this.configs.filter(
|
||||
x => x.type === "table"
|
||||
);
|
||||
|
||||
//-----------------------------
|
||||
// 编译
|
||||
//-----------------------------
|
||||
|
||||
this.rowConfigs.forEach(item => {
|
||||
|
||||
item.execute = FormulaCompiler.compile(
|
||||
item.formula
|
||||
);
|
||||
|
||||
this.rowMap.set(
|
||||
item.field,
|
||||
item
|
||||
);
|
||||
|
||||
});
|
||||
|
||||
//-----------------------------
|
||||
// 建立依赖图
|
||||
//-----------------------------
|
||||
|
||||
this.graph = new DependencyGraph(
|
||||
this.rowConfigs
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化计算整行
|
||||
*/
|
||||
calcAll(row) {
|
||||
|
||||
this.rowConfigs.forEach(item => {
|
||||
|
||||
row[item.field] = item.execute(row);
|
||||
|
||||
});
|
||||
|
||||
return row;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新一个字段
|
||||
*
|
||||
* field 发生变化
|
||||
*/
|
||||
update(row, field) {
|
||||
|
||||
const queue = [field];
|
||||
|
||||
const visited = new Set();
|
||||
|
||||
while (queue.length > 0) {
|
||||
|
||||
const current = queue.shift();
|
||||
|
||||
const nextFields = this.graph.getNext(current);
|
||||
|
||||
nextFields.forEach(nextField => {
|
||||
|
||||
if (visited.has(nextField))
|
||||
return;
|
||||
|
||||
visited.add(nextField);
|
||||
|
||||
const config = this.rowMap.get(nextField);
|
||||
|
||||
if (!config)
|
||||
return;
|
||||
|
||||
//-----------------------------------
|
||||
// 重新计算
|
||||
//-----------------------------------
|
||||
|
||||
row[nextField] = config.execute(row);
|
||||
|
||||
//-----------------------------------
|
||||
// 继续传播
|
||||
//-----------------------------------
|
||||
|
||||
queue.push(nextField);
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
return row;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新多个字段
|
||||
*/
|
||||
batchUpdate(row, fields = []) {
|
||||
|
||||
const queue = [...fields];
|
||||
|
||||
const visited = new Set();
|
||||
|
||||
while (queue.length > 0) {
|
||||
|
||||
const current = queue.shift();
|
||||
|
||||
const nextFields = this.graph.getNext(current);
|
||||
|
||||
nextFields.forEach(nextField => {
|
||||
|
||||
if (visited.has(nextField))
|
||||
return;
|
||||
|
||||
visited.add(nextField);
|
||||
|
||||
const config = this.rowMap.get(nextField);
|
||||
|
||||
if (!config)
|
||||
return;
|
||||
|
||||
row[nextField] = config.execute(row);
|
||||
|
||||
queue.push(nextField);
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
return row;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新Footer
|
||||
*/
|
||||
updateTable(rows) {
|
||||
|
||||
const footer = {};
|
||||
|
||||
this.tableConfigs.forEach(item => {
|
||||
|
||||
const formula = item.formula;
|
||||
|
||||
const match = formula.match(
|
||||
/(sum|avg|max|min|count)\((.*?)\)/
|
||||
);
|
||||
|
||||
if (!match)
|
||||
return;
|
||||
|
||||
const func = match[1];
|
||||
|
||||
const field = match[2];
|
||||
|
||||
if (typeof TableCalculator[func] !== "function")
|
||||
return;
|
||||
|
||||
footer[item.field] = TableCalculator[func](
|
||||
rows,
|
||||
field
|
||||
);
|
||||
|
||||
});
|
||||
|
||||
return footer;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 全部重新计算
|
||||
*/
|
||||
updateAll(rows) {
|
||||
|
||||
rows.forEach(row => {
|
||||
|
||||
this.calcAll(row);
|
||||
|
||||
});
|
||||
|
||||
return this.updateTable(rows);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
// src/formula/FormulaFunctions.js
|
||||
|
||||
/**
|
||||
* 内置函数
|
||||
*/
|
||||
const FormulaFunctions = {
|
||||
|
||||
// ------------------------
|
||||
// 数学
|
||||
// ------------------------
|
||||
|
||||
round(value, precision = 2) {
|
||||
value = Number(value || 0)
|
||||
return Number(value.toFixed(precision))
|
||||
},
|
||||
|
||||
abs(value) {
|
||||
return Math.abs(Number(value || 0))
|
||||
},
|
||||
|
||||
ceil(value) {
|
||||
return Math.ceil(Number(value || 0))
|
||||
},
|
||||
|
||||
floor(value) {
|
||||
return Math.floor(Number(value || 0))
|
||||
},
|
||||
|
||||
max(...args) {
|
||||
return Math.max(...args.map(v => Number(v || 0)))
|
||||
},
|
||||
|
||||
min(...args) {
|
||||
return Math.min(...args.map(v => Number(v || 0)))
|
||||
},
|
||||
|
||||
//----------------------------------
|
||||
// 判断
|
||||
//----------------------------------
|
||||
|
||||
if(condition, trueValue, falseValue) {
|
||||
return condition ? trueValue : falseValue
|
||||
},
|
||||
|
||||
//----------------------------------
|
||||
// 空值
|
||||
//----------------------------------
|
||||
|
||||
nvl(value, defaultValue = 0) {
|
||||
return value == null ? defaultValue : value
|
||||
},
|
||||
|
||||
//----------------------------------
|
||||
// 字符串
|
||||
//----------------------------------
|
||||
|
||||
len(str) {
|
||||
return (str || "").length
|
||||
},
|
||||
|
||||
upper(str) {
|
||||
return (str || "").toUpperCase()
|
||||
},
|
||||
|
||||
lower(str) {
|
||||
return (str || "").toLowerCase()
|
||||
},
|
||||
|
||||
concat(...args) {
|
||||
return args.join("")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default FormulaFunctions
|
||||
@@ -0,0 +1,54 @@
|
||||
// src/formula/FormulaValidator.js
|
||||
|
||||
import extractVariables from "./VariableExtractor"
|
||||
|
||||
/**
|
||||
* 检查公式是否合法
|
||||
*/
|
||||
export default class FormulaValidator {
|
||||
|
||||
/**
|
||||
* 校验
|
||||
*/
|
||||
static validate(configs) {
|
||||
|
||||
const errors = []
|
||||
|
||||
configs.forEach(item => {
|
||||
|
||||
if (!item.formula)
|
||||
return
|
||||
|
||||
try {
|
||||
|
||||
// 提取变量
|
||||
extractVariables(item.formula)
|
||||
|
||||
}
|
||||
catch (e) {
|
||||
|
||||
errors.push({
|
||||
|
||||
field: item.field,
|
||||
|
||||
formula: item.formula,
|
||||
|
||||
message: e.message
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
return {
|
||||
|
||||
success: errors.length == 0,
|
||||
|
||||
errors
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
// src/formula/TableCalculator.js
|
||||
|
||||
export default class TableCalculator {
|
||||
|
||||
//-------------------------
|
||||
// 求和
|
||||
//-------------------------
|
||||
|
||||
static sum(rows, field) {
|
||||
|
||||
return rows.reduce((total, row) => {
|
||||
|
||||
return total + Number(row[field] || 0)
|
||||
|
||||
}, 0)
|
||||
|
||||
}
|
||||
|
||||
//-------------------------
|
||||
// 平均
|
||||
//-------------------------
|
||||
|
||||
static avg(rows, field) {
|
||||
|
||||
if (!rows.length)
|
||||
return 0
|
||||
|
||||
return this.sum(rows, field) / rows.length
|
||||
|
||||
}
|
||||
|
||||
//-------------------------
|
||||
// 最大
|
||||
//-------------------------
|
||||
|
||||
static max(rows, field) {
|
||||
|
||||
if (!rows.length)
|
||||
return 0
|
||||
|
||||
return Math.max(
|
||||
|
||||
...rows.map(r => Number(r[field] || 0))
|
||||
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
//-------------------------
|
||||
// 最小
|
||||
//-------------------------
|
||||
|
||||
static min(rows, field) {
|
||||
|
||||
if (!rows.length)
|
||||
return 0
|
||||
|
||||
return Math.min(
|
||||
|
||||
...rows.map(r => Number(r[field] || 0))
|
||||
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
//-------------------------
|
||||
// 数量
|
||||
//-------------------------
|
||||
|
||||
static count(rows) {
|
||||
|
||||
return rows.length
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
// src/formula/VariableExtractor.js
|
||||
|
||||
/**
|
||||
* 提取变量
|
||||
*
|
||||
* qty*price
|
||||
*
|
||||
* =>
|
||||
*
|
||||
* ["qty","price"]
|
||||
*/
|
||||
|
||||
const keywords = [
|
||||
|
||||
"sum",
|
||||
"avg",
|
||||
"max",
|
||||
"min",
|
||||
"round",
|
||||
"abs",
|
||||
"ceil",
|
||||
"floor",
|
||||
"if",
|
||||
"nvl",
|
||||
"true",
|
||||
"false"
|
||||
|
||||
]
|
||||
|
||||
export default function extractVariables(formula) {
|
||||
|
||||
if (!formula)
|
||||
return []
|
||||
|
||||
const result = formula.match(/[a-zA-Z_][a-zA-Z0-9_]*/g) || []
|
||||
|
||||
return [...new Set(
|
||||
|
||||
result.filter(item => !keywords.includes(item))
|
||||
|
||||
)]
|
||||
|
||||
}
|
||||
|
||||
window.extractVariables = extractVariables
|
||||
@@ -0,0 +1,3 @@
|
||||
import FormulaEngine from "./FormulaEngine"
|
||||
|
||||
export default FormulaEngine
|
||||
@@ -1,8 +1,9 @@
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import { ref, unref } from "vue";
|
||||
import { ref, unref, computed } from "vue";
|
||||
import axios from "@/utils/axios";
|
||||
import { useUserStore } from "@/store/user";
|
||||
import { getDate, getDateTime } from "@/utils/time";
|
||||
import { getDataBySql } from "@/utils/doSql";
|
||||
|
||||
const userStore = useUserStore();
|
||||
|
||||
@@ -10,6 +11,19 @@ const loading = ref(false);
|
||||
const saving = ref(false);
|
||||
const error = ref(null);
|
||||
|
||||
|
||||
export async function getfieldvaluebyid(tablename,returnfield,keyfield,keyvalue) {
|
||||
const sql = `SELECT ${returnfield} FROM ${tablename} WHERE ${keyfield} = '${keyvalue}'`;
|
||||
// console.log(sql);
|
||||
const result = await getDataBySql(sql);
|
||||
|
||||
if (!result?.records?.length) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return Object.values(result.records[0])[0] ?? "";
|
||||
}
|
||||
|
||||
export async function getDefaultValue(targetRef, tablename) {
|
||||
try {
|
||||
loading.value = true;
|
||||
@@ -51,6 +65,7 @@ export async function getDefaultValue(targetRef, tablename) {
|
||||
|
||||
export async function checkMustField(targetObj, tablename) {
|
||||
const targetdata = unref(targetObj);
|
||||
console.log(targetObj);
|
||||
const params = {
|
||||
tableName: tablename || "v_bs_business",
|
||||
};
|
||||
@@ -77,6 +92,76 @@ export async function checkMustField(targetObj, tablename) {
|
||||
|
||||
return true;
|
||||
}
|
||||
export async function checkAllowRepeat(maintable, tableName) {
|
||||
// 获取不可重复字段
|
||||
const columnSql = `
|
||||
select col_FieldName,col_TableName,col_Caption
|
||||
from s_columnLib
|
||||
where col_AllowRepeat <> '1'
|
||||
and col_TableName='${tableName}'
|
||||
`;
|
||||
const result = await getDataBySql(columnSql);
|
||||
|
||||
const columns = result.records || [];
|
||||
|
||||
for (const column of columns) {
|
||||
const fieldName = column.col_FieldName;
|
||||
if (fieldName === "b_id") {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 当前表单值
|
||||
const value = maintable[fieldName];
|
||||
|
||||
// 空值跳过
|
||||
if (value === null || value === undefined || value === "") {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 查询数据库是否存在
|
||||
const checkSql = `
|
||||
select count(1) as num
|
||||
from ${tableName}
|
||||
where ${fieldName}='${value}' and b_id <> '${maintable.b_id}'
|
||||
`;
|
||||
|
||||
const result = await getDataBySql(checkSql);
|
||||
|
||||
const records = result?.records || [];
|
||||
|
||||
if (records.length > 0 && Number(records[0].num) > 0) {
|
||||
ElMessage.warning(`${column.col_Caption || fieldName} 已存在,不能重复`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export async function initReserveData(maintable, tableName) {
|
||||
const columnSql = `
|
||||
select col_FieldName,col_TableName,col_Caption
|
||||
from s_columnLib
|
||||
where col_NeedReserve = '1'
|
||||
and col_TableName='${tableName}'
|
||||
`;
|
||||
const result = await getDataBySql(columnSql);
|
||||
|
||||
const columns = result.records || [];
|
||||
|
||||
const reserveData = {};
|
||||
|
||||
columns.forEach((item) => {
|
||||
const fieldName = item.col_FieldName;
|
||||
|
||||
const value = maintable[fieldName];
|
||||
|
||||
if (value !== null && value !== undefined && value !== "") {
|
||||
reserveData[fieldName] = value;
|
||||
}
|
||||
});
|
||||
|
||||
return reserveData;
|
||||
}
|
||||
|
||||
export async function getMoneyExRate({
|
||||
rows = [],
|
||||
@@ -125,11 +210,6 @@ export function toMoney(val, scale = 3) {
|
||||
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() !== "";
|
||||
}
|
||||
@@ -138,25 +218,13 @@ 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 function handleBankInvChange(val, maintable, field) {
|
||||
if (field == "v_dw_name") {
|
||||
maintable.b_dw_bankacount = val?.b_bankacount || "";
|
||||
maintable.b_dw_invaccount = val?.b_invaccount || "";
|
||||
}
|
||||
if (field == "v_mycompanyname") {
|
||||
maintable.b_my_bankacount = val?.b_bankacount || "";
|
||||
maintable.b_my_invaccount = val?.b_invaccount || "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证集装箱号
|
||||
* ISO 6346 标准
|
||||
*
|
||||
* 格式:
|
||||
* 4位字母 + 7位数字
|
||||
*
|
||||
* @param {string} containerNo 集装箱号
|
||||
* @returns {boolean}
|
||||
*/
|
||||
@@ -170,55 +238,270 @@ export function checkContainerNo(containerNo) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const chars = value.substring(0, 10);
|
||||
// ISO 6346 字母对应值
|
||||
const letterMap = {
|
||||
A: 10,
|
||||
B: 12,
|
||||
C: 13,
|
||||
D: 14,
|
||||
E: 15,
|
||||
F: 16,
|
||||
G: 17,
|
||||
H: 18,
|
||||
I: 19,
|
||||
J: 20,
|
||||
K: 21,
|
||||
L: 23,
|
||||
M: 24,
|
||||
N: 25,
|
||||
O: 26,
|
||||
P: 27,
|
||||
Q: 28,
|
||||
R: 29,
|
||||
S: 30,
|
||||
T: 31,
|
||||
U: 32,
|
||||
V: 34,
|
||||
W: 35,
|
||||
X: 36,
|
||||
Y: 37,
|
||||
Z: 38,
|
||||
};
|
||||
|
||||
let sum = 0;
|
||||
|
||||
for (let i = 0; i < chars.length; i++) {
|
||||
// 前10位参与计算
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const char = value[i];
|
||||
|
||||
let num;
|
||||
|
||||
if (/[A-Z]/.test(chars[i])) {
|
||||
num = chars[i].charCodeAt(0) - 55;
|
||||
|
||||
// ISO6346 字母映射跳过 11、22、33
|
||||
if (num >= 11) num--;
|
||||
if (num >= 22) num--;
|
||||
if (num >= 33) num--;
|
||||
if (letterMap[char]) {
|
||||
num = letterMap[char];
|
||||
} else {
|
||||
num = Number(chars[i]);
|
||||
num = Number(char);
|
||||
}
|
||||
|
||||
// 权重 2^位置
|
||||
sum += num * Math.pow(2, i);
|
||||
}
|
||||
|
||||
// ISO 6346:
|
||||
// 校验码 = (总和 % 11) % 10
|
||||
const checkCode = (sum % 11) % 10;
|
||||
|
||||
return checkCode === Number(value[10]);
|
||||
}
|
||||
|
||||
// export function confirmSave(message = "数据已修改,是否保存?") {
|
||||
// return ElMessageBox.confirm(message, "提示", {
|
||||
// confirmButtonText: "保存",
|
||||
// cancelButtonText: "不保存",
|
||||
// type: "warning",
|
||||
// })
|
||||
// .then(() => {
|
||||
// return true; // 点击保存
|
||||
// })
|
||||
// .catch(() => {
|
||||
// return false; // 点击不保存或关闭
|
||||
// });
|
||||
// }
|
||||
export function confirmSave(message = "数据已修改,是否保存?") {
|
||||
return ElMessageBox.confirm(message, "提示", {
|
||||
confirmButtonText: "保存",
|
||||
cancelButtonText: "不保存",
|
||||
type: "warning",
|
||||
})
|
||||
.then(() => {
|
||||
return true; // 点击保存
|
||||
return new Promise((resolve) => {
|
||||
ElMessageBox({
|
||||
title: "提示",
|
||||
message,
|
||||
showCancelButton: true,
|
||||
showClose: true,
|
||||
confirmButtonText: "保存",
|
||||
cancelButtonText: "不保存",
|
||||
distinguishCancelAndClose: true,
|
||||
type: "warning",
|
||||
})
|
||||
.catch(() => {
|
||||
return false; // 点击不保存或关闭
|
||||
});
|
||||
.then(() => {
|
||||
// 保存
|
||||
resolve("save");
|
||||
})
|
||||
.catch((action) => {
|
||||
if (action === "cancel") {
|
||||
// 不保存
|
||||
resolve("noSave");
|
||||
} else if (action === "close") {
|
||||
// 点击右上角关闭
|
||||
resolve("cancel");
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// ---------------应收、应付、利润汇总
|
||||
export function handleFeeSummary(receiveRef, payRef, fields = {}) {
|
||||
return computed(() => {
|
||||
const data = calcFeeSummary(receiveRef.value, payRef.value, fields);
|
||||
|
||||
return {
|
||||
allHtml:
|
||||
formatCurrencyHtml(data.receive, data.receiveRmb, "应收") +
|
||||
formatCurrencyHtml(data.pay, data.payRmb, "应付") +
|
||||
formatCurrencyHtml(data.profit, data.profitRmb, "利润"),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// 币种金额HTML
|
||||
function formatCurrencyHtml(summary = {}, rmb, title = "") {
|
||||
let html = `<div class="g3currencytotal"><div>${title}合计:</div>`;
|
||||
|
||||
html += Object.entries(summary)
|
||||
.map(([currency, amount]) => {
|
||||
return `
|
||||
<div>${currency}:</div>
|
||||
<div>${Number(amount || 0).toFixed(2)}</div>
|
||||
<div class="g3currencytotalsx"></div>
|
||||
`;
|
||||
})
|
||||
.join("");
|
||||
|
||||
html += `
|
||||
<div>${title}折本币:</div>
|
||||
<div>${Number(rmb || 0).toFixed(2)}</div>
|
||||
</div>`;
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
export function handleYsYfSummary(receiveRef, payRef, fields = {}) {
|
||||
return computed(() => {
|
||||
const data = calcFeeSummary(receiveRef.value, payRef.value, fields);
|
||||
|
||||
return {
|
||||
allHtml: formatYsYfHtml(data.receive, "应收") + formatYsYfHtml(data.pay, "应付"),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// 币种金额HTML
|
||||
function formatYsYfHtml(summary = {}, title = "") {
|
||||
let html = `<div class="g3currencytotal"><div>${title}合计:</div>`;
|
||||
|
||||
html += Object.entries(summary)
|
||||
.map(([currency, amount], index, arr) => {
|
||||
return `
|
||||
<div>${currency}:</div>
|
||||
<div>${Number(amount || 0).toFixed(2)}</div>
|
||||
${index !== arr.length - 1 ? '<div class="g3currencytotalsx"></div>' : ""}
|
||||
`;
|
||||
})
|
||||
.join("");
|
||||
html += `</div>`;
|
||||
return html;
|
||||
}
|
||||
|
||||
// 应收、应付、利润汇总
|
||||
export function calcFeeSummary(receive = [], pay = [], fields = {}) {
|
||||
const {
|
||||
currencyField = "mx_moneytype_id",
|
||||
amountField = "mx_amount",
|
||||
rmbField = "mx_amount_rmb",
|
||||
typeField = "mx_type_id",
|
||||
} = fields;
|
||||
|
||||
const result = {
|
||||
receive: {},
|
||||
pay: {},
|
||||
profit: {},
|
||||
receiveRmb: 0,
|
||||
payRmb: 0,
|
||||
profitRmb: 0,
|
||||
};
|
||||
|
||||
const rows = [...(receive || []), ...(pay || [])];
|
||||
|
||||
rows.forEach((row) => {
|
||||
const currency = row[currencyField] || "未知币种";
|
||||
const amount = toMoney(row[amountField]);
|
||||
const rmb = toMoney(row[rmbField]);
|
||||
const type = row[typeField];
|
||||
|
||||
if (type === "应收") {
|
||||
result.receive[currency] = toMoney((result.receive[currency] || 0) + amount);
|
||||
|
||||
result.receiveRmb = toMoney(result.receiveRmb + rmb);
|
||||
}
|
||||
|
||||
if (type === "应付") {
|
||||
result.pay[currency] = toMoney((result.pay[currency] || 0) + amount);
|
||||
|
||||
result.payRmb = toMoney(result.payRmb + rmb);
|
||||
}
|
||||
});
|
||||
|
||||
// 利润 = 应收 - 应付
|
||||
const currencies = new Set([...Object.keys(result.receive), ...Object.keys(result.pay)]);
|
||||
|
||||
currencies.forEach((currency) => {
|
||||
result.profit[currency] = toMoney(
|
||||
(result.receive[currency] || 0) - (result.pay[currency] || 0),
|
||||
);
|
||||
});
|
||||
|
||||
result.profitRmb = toMoney(result.receiveRmb - result.payRmb);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export function handleDisabledState(stateGetter) {
|
||||
const editable = computed(() => ["草拟", "审核驳回"].includes(stateGetter()));
|
||||
|
||||
const approved = computed(() => stateGetter() === "审核通过");
|
||||
|
||||
return {
|
||||
editable,
|
||||
approved,
|
||||
};
|
||||
}
|
||||
|
||||
export function generateUuid() {
|
||||
if (window.crypto && crypto.getRandomValues) {
|
||||
const buf = new Uint8Array(16);
|
||||
crypto.getRandomValues(buf);
|
||||
|
||||
// 设置 UUID v4 标识位
|
||||
buf[6] = (buf[6] & 0x0f) | 0x40;
|
||||
buf[8] = (buf[8] & 0x3f) | 0x80;
|
||||
|
||||
const hex = Array.from(buf).map((b) => b.toString(16).padStart(2, "0"));
|
||||
|
||||
return [
|
||||
hex.slice(0, 4).join(""),
|
||||
hex.slice(4, 6).join(""),
|
||||
hex.slice(6, 8).join(""),
|
||||
hex.slice(8, 10).join(""),
|
||||
hex.slice(10, 16).join(""),
|
||||
].join("-");
|
||||
}
|
||||
|
||||
// 兼容老浏览器(360兼容模式等)
|
||||
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
||||
const r = (Math.random() * 16) | 0;
|
||||
const v = c === "x" ? r : (r & 0x3) | 0x8;
|
||||
return v.toString(16);
|
||||
});
|
||||
}
|
||||
// ------------------
|
||||
|
||||
// 默认导出所有方法
|
||||
export default {
|
||||
getDefaultValue,
|
||||
checkMustField,
|
||||
checkAllowRepeat,
|
||||
initReserveData,
|
||||
getMoneyExRate,
|
||||
toMoney,
|
||||
isEditableStateAndQR,
|
||||
isNotEmpty,
|
||||
getFieldString,
|
||||
handleBankInvChange,
|
||||
confirmSave,
|
||||
handleFeeSummary,
|
||||
handleYsYfSummary,
|
||||
handleDisabledState,
|
||||
};
|
||||
@@ -40,3 +40,25 @@ export function processGridKeydown(event, $table) {
|
||||
$table.setCurrentColumn(columns[toIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
export function processRowDrag(list, event, sortField = "mx_xh") {
|
||||
const { oldRow, newRow } = event;
|
||||
console.log("1111111111");
|
||||
|
||||
const oldIndex = list.indexOf(oldRow);
|
||||
const newIndex = list.indexOf(newRow);
|
||||
console.log(oldIndex);
|
||||
console.log(newIndex);
|
||||
|
||||
if (oldIndex < 0 || newIndex < 0 || oldIndex === newIndex) {
|
||||
return;
|
||||
}
|
||||
|
||||
const [row] = list.splice(oldIndex, 1);
|
||||
|
||||
list.splice(newIndex, 0, row);
|
||||
|
||||
list.forEach((item, index) => {
|
||||
item[sortField] = index + 1;
|
||||
});
|
||||
}
|
||||
@@ -1,980 +0,0 @@
|
||||
// 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 || "保存失败");
|
||||
}
|
||||
}
|
||||
@@ -55,7 +55,17 @@ export function getcheckdjid(strvalid = "") {
|
||||
}
|
||||
|
||||
export function getDateAfter(date, after = 0) {
|
||||
return dayjs(date).add(Number(after), "day").format("YYYY-MM-DD");
|
||||
if (!date) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const d = dayjs(date);
|
||||
|
||||
if (!d.isValid()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return d.add(Number(after), "day").format("YYYY-MM-DD");
|
||||
}
|
||||
|
||||
// 默认导出所有方法
|
||||
@@ -66,4 +76,4 @@ export default {
|
||||
formatToDate,
|
||||
formatToDateTime,
|
||||
getcheckdjid,
|
||||
};
|
||||
};
|
||||
Reference in new issue
Block a user