基础信息页:计量单位改 el-select(下拉历史+手动输入);表单排版重排为 4 行(类别占满行);类别末级英文后缀自动填规格型号
This commit is contained in:
@ -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)
|
||||
# ==============================================================================
|
||||
|
||||
@ -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):
|
||||
"""新增基础信息"""
|
||||
|
||||
@ -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'
|
||||
})
|
||||
}
|
||||
@ -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);
|
||||
|
||||
Reference in New Issue
Block a user