feat: 添加参考价格列 + 修复公司筛选跨域问题 + CLIP模型持久化
## 新增功能 - material_base 表新增 reference_price 列(NUMERIC(10,2)) - 基础信息 list.vue / buyOdoo.vue 页面增加「参考价格」列展示和编辑 - 新增 material_list:referencePrice 权限元素,支持按角色控制可见性 ## Bug 修复 - 入库三页面(buy/product/semi)公司筛选:非超管用户 company=ALL 不再传给旧版后端 - 基础信息两页面(list/buyOdoo):buyOdoo 增加 v-if=isSuperAdmin 与 list.vue 行为统一 - company=ALL 默认值在各页面 getList/fetchData 中自动过滤,兼容旧版后端 ## 运维优化 - docker-compose.prod.yml 增加 models_prod 卷挂载,CLIP模型持久化免重复上传 - deploy_code.sh 增加 models_prod 目录检查与模型文件存在性告警
This commit is contained in:
@ -21,6 +21,7 @@
|
||||
</el-input>
|
||||
|
||||
<el-select
|
||||
v-if="isSuperAdmin"
|
||||
v-model="queryParams.company"
|
||||
placeholder="所属公司"
|
||||
clearable
|
||||
@ -29,6 +30,7 @@
|
||||
style="width: 120px; margin-right: 10px;"
|
||||
@change="handleQuery"
|
||||
>
|
||||
<el-option label="全部 (跨域)" value="ALL" />
|
||||
<el-option v-for="item in companyOptions" :key="item" :label="item" :value="item" />
|
||||
</el-select>
|
||||
|
||||
@ -194,6 +196,7 @@
|
||||
<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('referencePrice')" v-model="columns.referencePrice.visible" label="参考价格" />
|
||||
<el-checkbox v-if="hasColPermission('warningStatus')" v-model="columns.warningStatus.visible" label="预警状态" />
|
||||
</div>
|
||||
</el-popover>
|
||||
@ -330,6 +333,12 @@
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-if="columns.referencePrice.visible" prop="referencePrice" label="参考价格" min-width="120" align="center" sortable="custom">
|
||||
<template #default="scope">
|
||||
<span v-if="scope.row.referencePrice != null" class="money-text">{{ scope.row.referencePrice?.toFixed(2) }}</span>
|
||||
<span v-else style="color: #ccc;">-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-if="columns.warningStatus.visible" label="预警状态" width="120" align="center">
|
||||
<template #default="{ row }">
|
||||
<template v-if="row.warningStatus === 2">
|
||||
@ -491,6 +500,14 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="参考价格" prop="referencePrice" v-if="hasFieldPermission('referencePrice')">
|
||||
<el-input-number v-model="form.referencePrice" :precision="2" :min="0" controls-position="right" style="width: 100%" placeholder="请输入参考价格" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-form-item label="产品图" prop="generalImage" v-if="hasFieldPermission('files')">
|
||||
<div class="upload-container" id="upload-generalImage">
|
||||
<el-upload
|
||||
@ -701,6 +718,7 @@ import ImageSearchDialog from '@/components/ImageSearchDialog.vue';
|
||||
import { imageSearch as imageSearchApi, type ImageSearchItem } from '@/api/common/upload';
|
||||
|
||||
const userStore = useUserStore();
|
||||
const isSuperAdmin = computed(() => userStore.role === 'SUPER_ADMIN');
|
||||
|
||||
// --- 类型定义 ---
|
||||
interface MaterialBaseVO {
|
||||
@ -723,6 +741,7 @@ interface MaterialBaseVO {
|
||||
warningOrdered?: boolean;
|
||||
warningRedEmails?: string;
|
||||
warningYellowEmails?: string;
|
||||
referencePrice?: number;
|
||||
}
|
||||
|
||||
interface QueryParams {
|
||||
@ -770,7 +789,8 @@ const fieldOptions = computed(() => {
|
||||
{ value: 'spec', label: '规格型号', perm: 'material_list:spec' },
|
||||
{ value: 'unit', label: '单位', perm: 'material_list:unit' },
|
||||
{ value: 'inventoryCount', label: '库存数', perm: 'material_list:inventoryCount' },
|
||||
{ value: 'availableCount', label: '可用数', perm: 'material_list:availableCount' }
|
||||
{ value: 'availableCount', label: '可用数', perm: 'material_list:availableCount' },
|
||||
{ value: 'referencePrice', label: '参考价格', perm: 'material_list:referencePrice' }
|
||||
];
|
||||
return allFields.filter(item => userStore.hasPermission(item.perm));
|
||||
});
|
||||
@ -803,7 +823,7 @@ const queryParams = reactive<QueryParams>({
|
||||
searchField: 'all',
|
||||
category: '',
|
||||
type: '',
|
||||
company: '',
|
||||
company: 'ALL',
|
||||
isEnabled: undefined,
|
||||
orderByColumn: '',
|
||||
isAsc: undefined,
|
||||
@ -925,7 +945,7 @@ const columns = reactive({
|
||||
commonName: { visible: true }, category: { visible: true }, type: { visible: true },
|
||||
spec: { visible: true }, unit: { visible: true }, inventory: { visible: true },
|
||||
available: { visible: true }, files: { visible: true }, isEnabled: { visible: true },
|
||||
isInspectionRequired: { visible: true }, warningStatus: { visible: true }
|
||||
isInspectionRequired: { visible: true }, referencePrice: { visible: true }, warningStatus: { visible: true }
|
||||
});
|
||||
|
||||
const permissionMap: Record<string, string> = {
|
||||
@ -933,7 +953,8 @@ const permissionMap: Record<string, string> = {
|
||||
commonName: 'material_list:commonName', category: 'material_list:category', type: 'material_list:type',
|
||||
spec: 'material_list:spec', unit: 'material_list:unit', inventory: 'material_list:inventoryCount',
|
||||
available: 'material_list:availableCount', files: 'material_list:files', isEnabled: 'material_list:isEnabled',
|
||||
isInspectionRequired: 'material_list:operation', warningStatus: 'material_list:view_warning'
|
||||
isInspectionRequired: 'material_list:operation', referencePrice: 'material_list:referencePrice',
|
||||
warningStatus: 'material_list:view_warning'
|
||||
};
|
||||
|
||||
const getStorageKey = () => `MOM_BASIC_INFO_COLS_${userStore.username || 'DEFAULT'}`;
|
||||
@ -1024,6 +1045,7 @@ const formRef = ref<FormInstance>();
|
||||
const initForm = {
|
||||
id: undefined, companyName: '', name: '', commonName: '', category: '', type: '', spec: '', unit: '',
|
||||
visibilityLevel: 0, generalManual: [] as string[], generalImage: [] as string[], isEnabled: true,
|
||||
referencePrice: undefined as number | undefined,
|
||||
productImageRemark: '', manualLinkRemark: ''
|
||||
};
|
||||
const form = ref({...initForm});
|
||||
@ -1096,6 +1118,10 @@ const getList = () => {
|
||||
...queryParams,
|
||||
advancedFilters: JSON.stringify(queryParams.advancedFilters || [])
|
||||
};
|
||||
// 兼容旧版后端:company=ALL 时不传过滤参数
|
||||
if (params.company === 'ALL') {
|
||||
delete params.company
|
||||
}
|
||||
listMaterialBase(params).then((response: any) => {
|
||||
if (response && response.data) {
|
||||
tableData.value = response.data.items;
|
||||
@ -1133,7 +1159,7 @@ const handleInputSearch = () => {
|
||||
};
|
||||
|
||||
const handleSortChange = ({ column, prop, order }: any) => {
|
||||
const sortableColumns = ['inventoryCount', 'availableCount', 'companyName', 'name', 'commonName', 'category', 'type', 'spec', 'unit'];
|
||||
const sortableColumns = ['inventoryCount', 'availableCount', 'referencePrice', 'companyName', 'name', 'commonName', 'category', 'type', 'spec', 'unit'];
|
||||
if (prop && sortableColumns.includes(prop)) {
|
||||
queryParams.orderByColumn = prop;
|
||||
queryParams.isAsc = order === 'ascending' ? 'asc' : order === 'descending' ? 'desc' : undefined;
|
||||
@ -1147,7 +1173,7 @@ const handleSortChange = ({ column, prop, order }: any) => {
|
||||
const handleQuery = () => { getList(); };
|
||||
const resetQuery = () => {
|
||||
queryParams.keyword = ''; queryParams.searchField = 'all'; queryParams.category = '';
|
||||
queryParams.type = ''; queryParams.company = ''; queryParams.isEnabled = undefined;
|
||||
queryParams.type = ''; queryParams.company = isSuperAdmin.value ? 'ALL' : ''; queryParams.isEnabled = undefined;
|
||||
queryParams.orderByColumn = ''; queryParams.isAsc = undefined; queryParams.has_stock = '';
|
||||
selectedItems.value = []; groupSelections.value = {};
|
||||
Object.values(tableRefs.value).forEach(t => t?.clearSelection?.());
|
||||
|
||||
Reference in New Issue
Block a user