Compare commits
2 Commits
6e50762da6
...
05aff2dd83
| Author | SHA1 | Date | |
|---|---|---|---|
| 05aff2dd83 | |||
| c1d364b786 |
BIN
deploy.tar.gz
BIN
deploy.tar.gz
Binary file not shown.
@ -252,7 +252,8 @@ class MaterialBaseService:
|
||||
|
||||
category = filters.get('category')
|
||||
if category is not None and category != '':
|
||||
query = query.filter(MaterialBase.category.ilike(category.strip()))
|
||||
# 在末尾拼接 '%' 实现前缀模糊匹配
|
||||
query = query.filter(MaterialBase.category.ilike(f"{category.strip()}%"))
|
||||
|
||||
type_val = filters.get('type')
|
||||
if type_val is not None and type_val != '':
|
||||
@ -750,7 +751,8 @@ class MaterialBaseService:
|
||||
|
||||
category = filters.get('category')
|
||||
if category is not None and category != '':
|
||||
filter_conditions.append(MaterialBase.category.ilike(category.strip()))
|
||||
# 同样在末尾拼接 '%'
|
||||
filter_conditions.append(MaterialBase.category.ilike(f"{category.strip()}%"))
|
||||
type_val = filters.get('type')
|
||||
if type_val is not None and type_val != '':
|
||||
filter_conditions.append(MaterialBase.material_type.ilike(type_val.strip()))
|
||||
|
||||
@ -239,7 +239,7 @@ const handleLogout = () => {
|
||||
<footer v-if="!isLoginPage" class="app-footer">
|
||||
<span class="version-tag">
|
||||
<el-icon style="vertical-align: middle; margin-right: 4px"><InfoFilled /></el-icon>
|
||||
当前版本:V3.35(识图版)
|
||||
当前版本:V3.36
|
||||
</span>
|
||||
</footer>
|
||||
|
||||
|
||||
@ -32,19 +32,16 @@
|
||||
<el-option v-for="item in companyOptions" :key="item" :label="item" :value="item" />
|
||||
</el-select>
|
||||
|
||||
<el-select
|
||||
v-model="queryParams.category"
|
||||
<el-cascader
|
||||
v-model="searchCategoryPath"
|
||||
:options="categoryTreeOptions"
|
||||
:props="{ checkStrictly: true }"
|
||||
placeholder="类别"
|
||||
clearable
|
||||
filterable
|
||||
allow-create
|
||||
default-first-option
|
||||
style="width: 240px; margin-right: 10px;"
|
||||
@change="handleQuery"
|
||||
popper-class="long-dropdown"
|
||||
>
|
||||
<el-option v-for="item in categoryOptions" :key="item" :label="item" :value="item" />
|
||||
</el-select>
|
||||
/>
|
||||
|
||||
<el-select
|
||||
v-model="queryParams.type"
|
||||
@ -171,21 +168,31 @@
|
||||
<el-button circle :icon="Setting" style="margin-left: 8px" title="列设置" />
|
||||
</template>
|
||||
<div class="column-setting-list">
|
||||
<div style="font-weight: bold; margin-bottom: 5px; border-bottom: 1px solid #eee; padding-bottom: 5px">
|
||||
列展示设置
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; font-weight: bold; margin-bottom: 5px; border-bottom: 1px solid #eee; padding-bottom: 5px">
|
||||
<span>列展示设置</span>
|
||||
<el-checkbox
|
||||
:model-value="isAllSelected"
|
||||
:indeterminate="isIndeterminate"
|
||||
@change="handleCheckAllChange"
|
||||
>
|
||||
全选
|
||||
</el-checkbox>
|
||||
</div>
|
||||
<el-checkbox v-model="columns.id.visible" label="ID" />
|
||||
<el-checkbox v-model="columns.companyName.visible" label="所属公司" />
|
||||
<el-checkbox v-model="columns.name.visible" label="名称" />
|
||||
<el-checkbox v-model="columns.commonName.visible" label="俗名" />
|
||||
<el-checkbox v-model="columns.category.visible" label="类别" />
|
||||
<el-checkbox v-model="columns.type.visible" label="类型" />
|
||||
<el-checkbox v-model="columns.spec.visible" label="规格型号" />
|
||||
<el-checkbox v-model="columns.unit.visible" label="单位" />
|
||||
<el-checkbox v-model="columns.inventory.visible" label="库存数" />
|
||||
<el-checkbox v-model="columns.available.visible" label="可用数" />
|
||||
<el-checkbox v-model="columns.files.visible" label="资料" />
|
||||
<el-checkbox v-model="columns.isEnabled.visible" label="状态" />
|
||||
|
||||
<el-checkbox v-if="hasColPermission('id')" v-model="columns.id.visible" label="ID" />
|
||||
<el-checkbox v-if="hasColPermission('companyName')" v-model="columns.companyName.visible" label="所属公司" />
|
||||
<el-checkbox v-if="hasColPermission('name')" v-model="columns.name.visible" label="名称" />
|
||||
<el-checkbox v-if="hasColPermission('commonName')" v-model="columns.commonName.visible" label="俗名" />
|
||||
<el-checkbox v-if="hasColPermission('category')" v-model="columns.category.visible" label="类别" />
|
||||
<el-checkbox v-if="hasColPermission('type')" v-model="columns.type.visible" label="类型" />
|
||||
<el-checkbox v-if="hasColPermission('spec')" v-model="columns.spec.visible" label="规格型号" />
|
||||
<el-checkbox v-if="hasColPermission('unit')" v-model="columns.unit.visible" label="单位" />
|
||||
<el-checkbox v-if="hasColPermission('inventory')" v-model="columns.inventory.visible" label="库存数" />
|
||||
<el-checkbox v-if="hasColPermission('available')" v-model="columns.available.visible" label="可用数" />
|
||||
<el-checkbox v-if="hasColPermission('files')" v-model="columns.files.visible" label="资料" />
|
||||
<el-checkbox v-if="hasColPermission('isEnabled')" v-model="columns.isEnabled.visible" label="状态" />
|
||||
<el-checkbox v-if="hasColPermission('isInspectionRequired')" v-model="columns.isInspectionRequired.visible" label="强制质检" />
|
||||
<el-checkbox v-if="hasColPermission('warningStatus')" v-model="columns.warningStatus.visible" label="预警状态" />
|
||||
</div>
|
||||
</el-popover>
|
||||
</div>
|
||||
@ -306,7 +313,7 @@
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-if="userStore.hasPermission('material_list:view_warning')" label="预警状态" width="120" align="center">
|
||||
<el-table-column v-if="columns.warningStatus.visible" label="预警状态" width="120" align="center">
|
||||
<template #default="{ row }">
|
||||
<template v-if="row.warningStatus === 2">
|
||||
<el-tag type="danger" size="small">红色预警</el-tag>
|
||||
@ -339,7 +346,7 @@
|
||||
<el-pagination
|
||||
v-model:current-page="queryParams.pageNum"
|
||||
v-model:page-size="queryParams.pageSize"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:page-sizes="[50, 100, 200, 500]"
|
||||
:background="true"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="total"
|
||||
@ -884,7 +891,8 @@ const columns = reactive({
|
||||
available: { visible: true },
|
||||
files: { visible: true },
|
||||
isEnabled: { visible: true },
|
||||
isInspectionRequired: { visible: true }
|
||||
isInspectionRequired: { visible: true },
|
||||
warningStatus: { visible: true }
|
||||
});
|
||||
|
||||
// 列与权限Code的映射关系(数据库中的code)
|
||||
@ -901,22 +909,78 @@ const permissionMap: Record<string, string> = {
|
||||
available: 'material_list:availableCount',
|
||||
files: 'material_list:files',
|
||||
isEnabled: 'material_list:isEnabled',
|
||||
isInspectionRequired: 'material_list:operation'
|
||||
isInspectionRequired: 'material_list:operation',
|
||||
warningStatus: 'material_list:view_warning'
|
||||
};
|
||||
|
||||
// 根据用户权限初始化列显示状态
|
||||
// ================= 全选与本地缓存逻辑 =================
|
||||
|
||||
// 获取唯一缓存 Key (加上用户名,防止同一个浏览器切换账号时设置错乱)
|
||||
const getStorageKey = () => `MOM_BASIC_INFO_COLS_${userStore.username || 'DEFAULT'}`;
|
||||
|
||||
// 辅助方法:判断当前用户是否有某列的权限
|
||||
const hasColPermission = (key: string) => {
|
||||
if (userStore.role === 'SUPER_ADMIN' || userStore.username === 'IRIS') return true;
|
||||
const code = permissionMap[key];
|
||||
return code ? !!userStore.hasPermission(code) : true;
|
||||
};
|
||||
|
||||
// 计算属性:判断是否"全选"了所有【有权限】的列
|
||||
const isAllSelected = computed(() => {
|
||||
const allowedKeys = Object.keys(columns).filter(k => hasColPermission(k));
|
||||
return allowedKeys.length > 0 && allowedKeys.every(k => columns[k as keyof typeof columns].visible);
|
||||
});
|
||||
|
||||
// 计算属性:判断是否"半选" (Element UI 中 checkbox 的 indeterminate 状态)
|
||||
const isIndeterminate = computed(() => {
|
||||
const allowedKeys = Object.keys(columns).filter(k => hasColPermission(k));
|
||||
const checkedCount = allowedKeys.filter(k => columns[k as keyof typeof columns].visible).length;
|
||||
return checkedCount > 0 && checkedCount < allowedKeys.length;
|
||||
});
|
||||
|
||||
// 事件:点击"全选"复选框时触发
|
||||
const handleCheckAllChange = (val: boolean) => {
|
||||
Object.keys(columns).forEach(key => {
|
||||
// 只有用户有权限的列,才会被全选/全不选操作控制
|
||||
if (hasColPermission(key)) {
|
||||
columns[key as keyof typeof columns].visible = val;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 监听:只要列展示状态发生变化,就自动保存到浏览器本地
|
||||
watch(columns, (newVal) => {
|
||||
localStorage.setItem(getStorageKey(), JSON.stringify(newVal));
|
||||
}, { deep: true });
|
||||
|
||||
// ================= 修改:权限初始化与读取缓存 =================
|
||||
|
||||
// 修改你原有的 initColumnPermissions 函数
|
||||
const initColumnPermissions = () => {
|
||||
// 超级管理员跳过权限检查,显示所有列
|
||||
if (userStore.role === 'SUPER_ADMIN' || userStore.username === 'IRIS') {
|
||||
return;
|
||||
// 1. 尝试从本地缓存读取用户上次的设置
|
||||
const cachedData = localStorage.getItem(getStorageKey());
|
||||
let parsedCache: Record<string, any> | null = null;
|
||||
if (cachedData) {
|
||||
try {
|
||||
parsedCache = JSON.parse(cachedData);
|
||||
} catch (e) {
|
||||
console.error('解析列缓存失败', e);
|
||||
}
|
||||
}
|
||||
|
||||
// 普通用户:严格执行列级权限控制,没有权限的列必须隐藏
|
||||
// 2. 遍历列进行权限判断与缓存赋值
|
||||
Object.keys(columns).forEach(key => {
|
||||
const code = permissionMap[key];
|
||||
if (code) {
|
||||
// 如果不具备该权限,必须设为 false
|
||||
columns[key].visible = !!userStore.hasPermission(code);
|
||||
const colKey = key as keyof typeof columns;
|
||||
const hasPerm = hasColPermission(colKey);
|
||||
|
||||
if (!hasPerm) {
|
||||
// 【权限最高】如果没有权限,强制隐藏,无视任何缓存
|
||||
columns[colKey].visible = false;
|
||||
} else {
|
||||
// 如果有权限,且存在本地缓存,则使用本地缓存的值
|
||||
if (parsedCache && parsedCache[colKey] !== undefined) {
|
||||
columns[colKey].visible = parsedCache[colKey].visible;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
@ -939,6 +1003,16 @@ const categoryOptions = ref<string[]>([]);
|
||||
const typeOptions = ref<string[]>([]);
|
||||
const categoryTreeOptions = ref<CascaderOption[]>([]);
|
||||
|
||||
// 用于搜索栏级联选择器的数据绑定中转
|
||||
const searchCategoryPath = computed({
|
||||
get() {
|
||||
return queryParams.category ? queryParams.category.split('/') : [];
|
||||
},
|
||||
set(val: string[] | null) {
|
||||
queryParams.category = val && val.length > 0 ? val.join('/') : '';
|
||||
}
|
||||
});
|
||||
|
||||
// 类别级联选择器的 ref
|
||||
const categoryCascaderRef = ref<any>(null);
|
||||
|
||||
@ -954,7 +1028,7 @@ const tempCategorySuffix = ref<string>('');
|
||||
|
||||
const queryParams = reactive<QueryParams>({
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
pageSize: 100,
|
||||
keyword: '',
|
||||
searchField: 'all',
|
||||
category: '',
|
||||
|
||||
Reference in New Issue
Block a user