落地空运单聊询价字段与线路选择。

必填核对后再建单;多条线路走 H5 点选;费用只展示该线路 TMS 回包,不套用整单空运费。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-22 15:02:32 +08:00
co-authored by Cursor
parent 8afe909230
commit cfbce2fd69
53 changed files with 3470 additions and 372 deletions
@@ -25,6 +25,7 @@ import {
} from "/@/views/inquiry/shared/dataPermCatalog";
import ProtoIcon from "/@/views/inquiry/components/ProtoIcon.vue";
import AdminModal from "/@/views/inquiry/components/AdminModal.vue";
import { joinPermissionIds } from "/@/views/inquiry/role/rolePermission";
const rows = ref<RoleRow[]>([]);
const loading = ref(false);
@@ -37,6 +38,8 @@ const form = reactive({
roleCode: "",
status: "active" as RoleRow["status"],
checkedKeys: [] as string[],
/** 打开弹窗时已授权菜单,供 saveRolePermission 增量对比 */
lastPermissionIds: [] as string[],
dataPerms: [] as string[],
/** 旧后台独立项:系统异常消息通知 */
systemExceptionNotify: false,
@@ -157,6 +160,7 @@ function openCreate() {
roleCode: "",
status: "active",
checkedKeys: [],
lastPermissionIds: [],
dataPerms: [],
systemExceptionNotify: false,
});
@@ -171,14 +175,18 @@ async function openEdit(row: RoleRow) {
roleCode: row.roleCode,
status: row.status,
checkedKeys: [] as string[],
lastPermissionIds: [] as string[],
dataPerms: routeDataPermsOnly(allPerms),
systemExceptionNotify: allPerms.includes(SYSTEM_EXCEPTION_NOTIFY_KEY),
});
try {
const perms: any = await queryRolePermission({ roleId: row.id });
form.checkedKeys = (Array.isArray(perms) ? perms : perms?.result || []).map(String);
const ids = (Array.isArray(perms) ? perms : perms?.result || []).map(String);
form.checkedKeys = ids;
form.lastPermissionIds = [...ids];
} catch {
form.checkedKeys = [];
form.lastPermissionIds = [];
}
modalOpen.value = true;
}
@@ -201,12 +209,12 @@ async function save() {
},
Boolean(editing.value),
);
const roleId = editing.value?.id || saved?.id || saved?.result?.id;
if (roleId && form.checkedKeys.length) {
const roleId = String(editing.value?.id || saved?.id || saved?.result?.id || "");
if (roleId) {
await saveRolePermission({
roleId,
permissionIds: form.checkedKeys.join(","),
lastpermissionIds: "",
permissionIds: joinPermissionIds(form.checkedKeys),
lastpermissionIds: form.lastPermissionIds.join(","),
});
}
message.success(editing.value ? "角色已更新" : "角色已创建");
@@ -0,0 +1,21 @@
/**
* 角色菜单权限保存辅助:统一 a-tree 勾选值,并拼成 Jeecg saveRolePermission 所需字符串。
* 询价角色页与 Jeecg 原生 RolePermissionDrawer 对齐 lastpermissionIds 增量语义。
*/
/** a-tree / BasicTree 勾选结果可能是数组,或 checkStrictly 下的 { checked, halfChecked } */
export function normalizeMenuCheckedKeys(checked: unknown): string[] {
if (Array.isArray(checked)) {
return checked.map(String).filter(Boolean);
}
if (checked && typeof checked === 'object' && 'checked' in checked) {
const box = checked as { checked?: unknown[] };
return (box.checked || []).map(String).filter(Boolean);
}
return [];
}
/** 提交 saveRolePermission.permissionIds */
export function joinPermissionIds(checked: unknown): string {
return normalizeMenuCheckedKeys(checked).join(',');
}
@@ -0,0 +1,18 @@
import {
joinPermissionIds,
normalizeMenuCheckedKeys,
} from '/@/views/inquiry/role/rolePermission';
test('normalizeMenuCheckedKeys accepts flat array', () => {
expect(normalizeMenuCheckedKeys(['a', 'b'])).toEqual(['a', 'b']);
});
test('normalizeMenuCheckedKeys accepts checkStrictly object', () => {
expect(
normalizeMenuCheckedKeys({ checked: ['x', 'y'], halfChecked: ['p'] }),
).toEqual(['x', 'y']);
});
test('joinPermissionIds builds comma list', () => {
expect(joinPermissionIds(['id1', 'id2'])).toBe('id1,id2');
});