基础信息页:计量单位改 el-select(下拉历史+手动输入);表单排版重排为 4 行(类别占满行);类别末级英文后缀自动填规格型号

This commit is contained in:
DXC
2026-06-04 13:22:51 +08:00
parent 1c0c02fd36
commit bac670ef7a
4 changed files with 113 additions and 28 deletions

View File

@ -98,6 +98,24 @@ def search_base():
return jsonify({"code": 500, "msg": str(e)}), 500
# ==============================================================================
# 1.1 计量单位字典接口 (GET /api/v1/inbound/base/units)
# ==============================================================================
@inbound_base_bp.route('/units', methods=['GET'])
@permission_required('material_list')
def get_unit_dict():
"""
获取所有已存在的非空计量单位(去重 + 排序),用于前端
新增/编辑弹窗中"计量单位"下拉框的历史记录。
"""
try:
units = MaterialBaseService.get_distinct_units()
return jsonify({"code": 200, "msg": "success", "data": units})
except Exception as e:
traceback.print_exc()
return jsonify({"code": 500, "msg": str(e)}), 500
# ==============================================================================
# 2. 列表接口 (GET /api/v1/inbound/base/list)
# ==============================================================================

View File

@ -528,6 +528,29 @@ class MaterialBaseService:
traceback.print_exc()
return {"categories": [], "types": [], "companies": []}
@staticmethod
def get_distinct_units():
"""
获取所有已存在且非空的计量单位(去重 + 排序)。
用于前端"基础信息"新增/编辑弹窗的"计量单位"下拉历史记录。
SQL 语义:
SELECT DISTINCT unit FROM material_base
WHERE unit IS NOT NULL AND unit != ''
ORDER BY unit ASC
"""
try:
rows = db.session.query(MaterialBase.unit) \
.filter(MaterialBase.unit.isnot(None), MaterialBase.unit != '') \
.distinct() \
.all()
sorted_units = sorted([u[0] for u in rows if u[0]])
return sorted_units
except Exception as e:
traceback.print_exc()
print(f"查询计量单位字典失败: {e}")
return []
@staticmethod
def create_material(data):
"""新增基础信息"""

View File

@ -87,3 +87,11 @@ export function markWarningOrdered(data: { baseId: number; isOrdered: boolean })
data
})
}
// 9. 获取计量单位字典 (新增/编辑弹窗下拉历史)
export function getMaterialUnitsAPI() {
return request({
url: '/inbound/base/units',
method: 'get'
})
}

View File

@ -409,6 +409,20 @@
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="类型" prop="type" v-if="hasFieldPermission('type')">
<el-autocomplete
v-model="form.type"
:fetch-suggestions="querySearchType"
placeholder="可输入或选择"
clearable
style="width: 100%"
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="类别" prop="category" v-if="hasFieldPermission('category')">
<div style="display: flex; width: 100%; align-items: center;">
<el-cascader
@ -430,26 +444,6 @@
style="width: 50%;"
/>
</div>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="类型" prop="type" v-if="hasFieldPermission('type')">
<el-autocomplete
v-model="form.type"
:fetch-suggestions="querySearchType"
placeholder="可输入或选择"
clearable
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="规格型号" prop="spec" v-if="hasFieldPermission('spec')">
<el-input v-model="form.spec" placeholder="请输入规格型号" />
</el-form-item>
</el-col>
</el-row>
@ -457,13 +451,26 @@
<el-row>
<el-col :span="12">
<el-form-item label="计量单位" prop="unit" v-if="hasFieldPermission('unit')">
<el-input v-model="form.unit" placeholder=": , , " />
<el-select
v-model="form.unit"
filterable
allow-create
default-first-option
placeholder="请选择或输入计量单位"
style="width: 100%"
>
<el-option
v-for="item in unitOptions"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item v-if="false" label="可见等级" prop="visibilityLevel">
<el-input-number v-model="form.visibilityLevel" :min="0" :max="9" label="等级" />
<span style="margin-left: 10px; color: #999; font-size: 12px;">(0低-9高)</span>
<el-form-item label="规格型号" prop="spec" v-if="hasFieldPermission('spec')">
<el-input v-model="form.spec" placeholder="请输入规格型号" />
</el-form-item>
</el-col>
</el-row>
@ -669,7 +676,8 @@ import {
exportAssetStatistics,
batchSetWarning,
batchSetInspection,
markWarningOrdered
markWarningOrdered,
getMaterialUnitsAPI
} from '@/api/material_base';
import { uploadFile, deleteFile } from '@/api/common/upload';
import { usePasteUpload } from '@/hooks/usePasteUpload';
@ -1003,6 +1011,7 @@ const hasFieldPermission = (field: string) => {
const companyOptions = ref<string[]>([]);
const categoryOptions = ref<string[]>([]);
const typeOptions = ref<string[]>([]);
const unitOptions = ref<string[]>([]);
const categoryTreeOptions = ref<CascaderOption[]>([]);
// 用于搜索栏级联选择器的数据绑定中转
@ -1018,10 +1027,25 @@ const searchCategoryPath = computed({
// 类别级联选择器的 ref
const categoryCascaderRef = ref<any>(null);
// 选中类别后自动收起下拉面板
// 选中类别后1) 收起下拉面板2) 自动提取末级 Label 末尾的英文字母填入规格型号
const onCategoryChange = () => {
if (categoryCascaderRef.value) {
categoryCascaderRef.value.togglePopperVisible(false);
if (!categoryCascaderRef.value) return;
// 1) 收起下拉
categoryCascaderRef.value.togglePopperVisible(false);
// 2) 从末级节点 Label 提取英文字母后缀 (例如 "电子半成品HH" -> "HH"),写入规格型号
// 仅在 @change 触发时赋一次值,用户可继续手动修改;未匹配到则保持原值
try {
const nodes = categoryCascaderRef.value.getCheckedNodes?.() || [];
const node = nodes[0];
const label: string = (node && node.label) || '';
const match = label.match(/[a-zA-Z]+$/);
if (match) {
form.value.spec = match[0];
}
} catch (e) {
console.error('提取类别英文后缀失败', e);
}
};
@ -1127,6 +1151,17 @@ const getOptionsList = () => {
});
};
// 获取计量单位字典(新增/编辑弹窗下拉历史)
const fetchUnitList = () => {
getMaterialUnitsAPI().then((res: any) => {
if (res.code === 200) {
unitOptions.value = res.data || [];
}
}).catch(err => {
console.error("获取计量单位字典失败", err);
});
};
const querySearchCompany = (queryString: string, cb: any) => {
const results = queryString
? companyOptions.value.filter(item => item.toLowerCase().includes(queryString.toLowerCase()))
@ -1834,6 +1869,7 @@ onMounted(() => {
getList();
}
getOptionsList();
fetchUnitList();
// 2. 修复弹窗锁定逻辑
console.log('--- 准备检测外部跳转参数 ---', route.query);