将半成品成品同样进行新增所属公司以及内容修改
This commit is contained in:
@ -105,11 +105,6 @@
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<template #default="scope" v-else-if="col.prop === 'company_name'">
|
||||
<el-tag v-if="scope.row.company_name" type="info" effect="plain" size="small" style="font-weight: bold;">{{ scope.row.company_name }}</el-tag>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
|
||||
<template #default="scope" v-else-if="col.prop === 'sn_bn'">
|
||||
<div v-if="scope.row.serial_number" class="id-cell">
|
||||
<span class="prefix-tag sn">SN</span>
|
||||
|
||||
@ -2,16 +2,28 @@
|
||||
<div class="product-module">
|
||||
<div class="header-tools">
|
||||
<div class="left-tools">
|
||||
<el-select
|
||||
v-model="queryParams.company"
|
||||
placeholder="所属公司"
|
||||
class="filter-item-select"
|
||||
clearable
|
||||
filterable
|
||||
@change="fetchData"
|
||||
style="width: 160px;"
|
||||
>
|
||||
<el-option v-for="item in companyOptions" :key="item" :label="item" :value="item" />
|
||||
</el-select>
|
||||
|
||||
<el-input
|
||||
v-model="queryParams.keyword"
|
||||
placeholder="🔍 搜索物料 / SN / 工单 / 订单号..."
|
||||
class="search-input"
|
||||
placeholder="🔍 搜索物料 / SN / 工单..."
|
||||
class="filter-item-input"
|
||||
clearable
|
||||
@clear="fetchData"
|
||||
@keyup.enter="fetchData"
|
||||
style="width: 300px; margin-right: 10px;"
|
||||
style="width: 260px;"
|
||||
>
|
||||
<template #append><el-button :icon="Search" @click="fetchData" /></template>
|
||||
<template #prefix><el-icon><Search /></el-icon></template>
|
||||
</el-input>
|
||||
|
||||
<el-select
|
||||
@ -66,6 +78,11 @@
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<template #default="scope" v-else-if="col.prop === 'company_name'">
|
||||
<el-tag v-if="scope.row.company_name" type="info" effect="plain" size="small" style="font-weight: bold;">{{ scope.row.company_name }}</el-tag>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
|
||||
<template #default="scope" v-else-if="['serial_number'].includes(col.prop)">
|
||||
<div v-if="scope.row.serial_number" class="id-cell">
|
||||
<span class="prefix-tag sn">SN</span>
|
||||
@ -133,21 +150,27 @@
|
||||
|
||||
<el-pagination class="pagination-bar" v-model:current-page="queryParams.page" v-model:page-size="queryParams.pageSize" :total="total" layout="total, sizes, prev, pager, next" background @change="fetchData" />
|
||||
|
||||
<el-dialog v-model="visible" :title="dialogStatus === 'create' ? '成品入库' : '编辑成品'" width="1100px" top="5vh" :close-on-click-modal="false" class="stylish-dialog">
|
||||
<el-dialog v-model="visible" :title="dialogStatus === 'create' ? '成品入库' : '编辑成品'" width="1100px" top="5vh" :close-on-click-modal="false" class="stylish-dialog compact-layout">
|
||||
<div class="dialog-scroll-container">
|
||||
<el-form :model="form" label-width="110px" ref="formRef" :rules="rules" size="default" class="stylish-form">
|
||||
|
||||
<div class="form-card basic-card">
|
||||
<div class="card-title"><el-icon class="icon"><Box /></el-icon><span>1. 基础信息</span></div>
|
||||
<div class="card-title">
|
||||
<div style="display: flex; align-items: center;">
|
||||
<el-icon class="icon"><Box /></el-icon>
|
||||
<span>1. 基础信息</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<el-row :gutter="24" v-if="dialogStatus === 'create'" style="margin-bottom: 20px;">
|
||||
<el-col :span="10">
|
||||
<el-form-item label="物料搜索" prop="base_id">
|
||||
<el-form-item label="物料搜索" prop="base_id" class="highlight-label">
|
||||
<el-select
|
||||
v-model="form.base_id"
|
||||
filterable
|
||||
remote
|
||||
reserve-keyword
|
||||
clearable
|
||||
placeholder="搜名称/规格..."
|
||||
:remote-method="handleSearchMaterial"
|
||||
@visible-change="handleMaterialDropdownVisible"
|
||||
@ -155,15 +178,28 @@
|
||||
style="width: 100%"
|
||||
@change="onMaterialSelected"
|
||||
default-first-option
|
||||
v-loadmore="loadMoreMaterials"
|
||||
popper-class="long-dropdown"
|
||||
>
|
||||
<template #prefix><el-icon><Search /></el-icon></template>
|
||||
<el-option v-for="item in materialOptions" :key="item.id" :label="item.name" :value="item.id">
|
||||
<div class="option-item">
|
||||
<span class="opt-name">{{ item.name }}</span>
|
||||
<span class="opt-spec">{{ item.spec }}</span>
|
||||
<el-tag v-if="item.isHistory" size="small" type="info" effect="plain">历史</el-tag>
|
||||
<el-tag v-else size="small" type="success" effect="plain">系统</el-tag>
|
||||
<div class="opt-main">
|
||||
<span class="opt-name" :title="item.name">{{ item.name }}</span>
|
||||
</div>
|
||||
<div class="opt-meta">
|
||||
<span class="opt-spec" :title="item.spec">{{ item.spec || '-' }}</span>
|
||||
</div>
|
||||
<div class="opt-tags">
|
||||
<el-tag size="small" type="info" effect="light" class="company-tag">{{ item.company_name }}</el-tag>
|
||||
<el-tag v-if="item.isHistory" size="small" type="info" effect="plain">历史</el-tag>
|
||||
<el-tag v-else size="small" type="success" effect="plain">系统</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
</el-option>
|
||||
<div v-if="loadingMore" style="text-align: center; color: #999; font-size: 12px; padding: 8px; background: #f9f9f9;">
|
||||
<el-icon class="is-loading"><Refresh /></el-icon> 加载更多中...
|
||||
</div>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@ -175,11 +211,12 @@
|
||||
</el-row>
|
||||
<div class="read-only-grid">
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="8"><el-form-item label="名称"><el-input v-model="form.material_name" disabled class="is-text-view" /></el-form-item></el-col>
|
||||
<el-col :span="8"><el-form-item label="规格"><el-input v-model="form.spec_model" disabled class="is-text-view" /></el-form-item></el-col>
|
||||
<el-col :span="8"><el-form-item label="单位"><el-input v-model="form.unit" disabled class="is-text-view" /></el-form-item></el-col>
|
||||
<el-col :span="8"><el-form-item label="类型"><el-input v-model="form.material_type" disabled class="is-text-view" /></el-form-item></el-col>
|
||||
<el-col :span="8"><el-form-item label="类别"><el-input v-model="form.category" disabled class="is-text-view" /></el-form-item></el-col>
|
||||
<el-col :span="8"><el-form-item label="所属公司"><el-input v-model="form.company_name" readonly class="is-text-view" /></el-form-item></el-col>
|
||||
<el-col :span="8"><el-form-item label="名称"><el-input v-model="form.material_name" readonly class="is-text-view" /></el-form-item></el-col>
|
||||
<el-col :span="8"><el-form-item label="规格"><el-input v-model="form.spec_model" readonly class="is-text-view" /></el-form-item></el-col>
|
||||
<el-col :span="8"><el-form-item label="单位"><el-input v-model="form.unit" readonly class="is-text-view" /></el-form-item></el-col>
|
||||
<el-col :span="8"><el-form-item label="类型"><el-input v-model="form.material_type" readonly class="is-text-view" /></el-form-item></el-col>
|
||||
<el-col :span="8"><el-form-item label="类别"><el-input v-model="form.category" readonly class="is-text-view" /></el-form-item></el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
@ -190,8 +227,8 @@
|
||||
<div class="card-content">
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="6"><el-form-item label="SKU" prop="sku"><el-input v-model="form.sku" placeholder="自动生成" disabled /></el-form-item></el-col>
|
||||
<el-col :span="6"><el-form-item label="条码" prop="barcode"><el-input v-model="form.barcode" placeholder="自动生成" /></el-form-item></el-col>
|
||||
<el-col :span="6"><el-form-item label="库位" prop="warehouse_location"><el-input v-model="form.warehouse_location" /></el-form-item></el-col>
|
||||
<el-col :span="6"><el-form-item label="条码" prop="barcode"><el-input v-model="form.barcode" placeholder="自动生成" clearable /></el-form-item></el-col>
|
||||
<el-col :span="6"><el-form-item label="库位" prop="warehouse_location"><el-input v-model="form.warehouse_location" placeholder="例如: B-01-01" clearable /></el-form-item></el-col>
|
||||
<el-col :span="6"><el-form-item label="入库日期"><el-date-picker v-model="form.in_date" type="date" value-format="YYYY-MM-DD" style="width:100%" disabled /></el-form-item></el-col>
|
||||
</el-row>
|
||||
|
||||
@ -389,22 +426,53 @@ import {
|
||||
updateProductInbound,
|
||||
deleteProductInbound,
|
||||
searchMaterialBase,
|
||||
searchBom // [新增]
|
||||
searchBom,
|
||||
getFilterOptions // [新增]
|
||||
} from '@/api/inbound/product'
|
||||
import { uploadFile, deleteFile } from '@/api/inbound/buy'
|
||||
import WebRtcCamera from '@/components/Camera/WebRtcCamera.vue'
|
||||
import { getLabelPreview, executePrint } from '@/api/common/print'
|
||||
|
||||
// ------------------------------------
|
||||
// v-loadmore
|
||||
// ------------------------------------
|
||||
const vLoadmore = {
|
||||
mounted(el: any, binding: any) {
|
||||
const checkAndBind = () => {
|
||||
const dropDownWrap = document.querySelector('.long-dropdown .el-select-dropdown__wrap')
|
||||
if (dropDownWrap && !dropDownWrap.getAttribute('data-loadmore-bound')) {
|
||||
dropDownWrap.setAttribute('data-loadmore-bound', 'true')
|
||||
dropDownWrap.addEventListener('scroll', function (this: any) {
|
||||
const condition = this.scrollHeight - this.scrollTop <= this.clientHeight + 1
|
||||
if (condition) {
|
||||
binding.value()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
setTimeout(checkAndBind, 500)
|
||||
el.addEventListener('click', () => setTimeout(checkAndBind, 300))
|
||||
}
|
||||
}
|
||||
|
||||
const loading = ref(false)
|
||||
const submitting = ref(false)
|
||||
const visible = ref(false)
|
||||
const searchLoading = ref(false)
|
||||
const loadingMore = ref(false)
|
||||
const dialogStatus = ref<'create' | 'update'>('create')
|
||||
const tableData = ref([])
|
||||
const total = ref(0)
|
||||
const formRef = ref()
|
||||
const queryParams = reactive({ page: 1, pageSize: 100, keyword: '', statuses: ['在库', '借库'] })
|
||||
const queryParams = reactive({ page: 1, pageSize: 100, keyword: '', statuses: ['在库', '借库'], company: '' })
|
||||
const categoryOptions = ref<string[]>([])
|
||||
const typeOptions = ref<string[]>([])
|
||||
const companyOptions = ref<string[]>([]) // [新增]
|
||||
const materialOptions = ref<any[]>([])
|
||||
const searchPage = ref(1)
|
||||
const searchKeyword = ref('')
|
||||
const hasNextPage = ref(true)
|
||||
let searchTimer: any = null
|
||||
|
||||
// BOM 搜索相关
|
||||
const bomSearchLoading = ref(false)
|
||||
@ -432,6 +500,7 @@ const inspection_url = ref('')
|
||||
|
||||
// [核心优化] 所有列定义
|
||||
const allColumns = [
|
||||
{ prop: 'company_name', label: '所属公司', minWidth: '100' }, // [新增]
|
||||
{ prop: 'material_name', label: '名称', minWidth: '140' },
|
||||
{ prop: 'sku', label: 'SKU', minWidth: '110' },
|
||||
{ prop: 'serial_number', label: '序列号', minWidth: '130' },
|
||||
@ -454,11 +523,13 @@ const allColumns = [
|
||||
{ prop: 'detail_link', label: '详情', minWidth: '100' }
|
||||
]
|
||||
|
||||
const defaultVisibleCols = ['material_name', 'sku', 'serial_number', 'qty_stock', 'status', 'quality_status', 'product_photo', 'sale_price', 'order_id']
|
||||
const defaultVisibleCols = ['company_name', 'material_name', 'sku', 'serial_number', 'qty_stock', 'status', 'quality_status', 'product_photo', 'sale_price', 'order_id']
|
||||
const visibleColumnProps = ref(defaultVisibleCols)
|
||||
|
||||
const form = reactive({
|
||||
id: undefined, base_id: undefined, material_name: '', spec_model: '', material_type: '', category: '', unit: '',
|
||||
id: undefined, base_id: undefined,
|
||||
company_name: '', // [新增]
|
||||
material_name: '', spec_model: '', material_type: '', category: '', unit: '',
|
||||
sku: '', barcode: '', serial_number: '', in_date: '',
|
||||
in_quantity: 1, stock_quantity: 1, available_quantity: 1,
|
||||
warehouse_location: '', status: '在库', quality_status: '合格',
|
||||
@ -513,18 +584,53 @@ const rules = {
|
||||
// ------------------------------------
|
||||
// Material Search & Population Logic
|
||||
// ------------------------------------
|
||||
const handleMaterialDropdownVisible = (visible: boolean) => { if (visible && materialOptions.value.length === 0) handleSearchMaterial('') }
|
||||
const handleMaterialDropdownVisible = (visible: boolean) => { if (visible && materialOptions.value.length === 0) handleSearchMaterialDebounced('') }
|
||||
|
||||
const handleSearchMaterialDebounced = (query: string) => {
|
||||
if (searchTimer) clearTimeout(searchTimer)
|
||||
searchTimer = setTimeout(() => {
|
||||
handleSearchMaterial(query)
|
||||
}, 300)
|
||||
}
|
||||
|
||||
const handleSearchMaterial = async (query: string) => {
|
||||
searchLoading.value = true
|
||||
searchKeyword.value = query
|
||||
searchPage.value = 1
|
||||
materialOptions.value = []
|
||||
|
||||
try {
|
||||
const res: any = await searchMaterialBase(query)
|
||||
const res: any = await searchMaterialBase(query, 1)
|
||||
const apiResults = (res.data || []).map((i: any) => ({ ...i, isHistory: false }))
|
||||
materialOptions.value = apiResults
|
||||
hasNextPage.value = res.has_next
|
||||
} finally { searchLoading.value = false }
|
||||
}
|
||||
|
||||
const loadMoreMaterials = async () => {
|
||||
if (searchLoading.value || loadingMore.value || !hasNextPage.value) return
|
||||
loadingMore.value = true
|
||||
searchPage.value += 1
|
||||
try {
|
||||
const res: any = await searchMaterialBase(searchKeyword.value, searchPage.value)
|
||||
if (res.data && res.data.length > 0) {
|
||||
const newItems = res.data.map((i: any) => ({...i, isHistory: false}))
|
||||
materialOptions.value.push(...newItems)
|
||||
hasNextPage.value = res.has_next
|
||||
} else {
|
||||
hasNextPage.value = false
|
||||
}
|
||||
} catch (e) {
|
||||
searchPage.value -= 1
|
||||
} finally {
|
||||
loadingMore.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const onMaterialSelected = (val: number) => {
|
||||
const item = materialOptions.value.find(i => i.id === val)
|
||||
if (item) {
|
||||
form.company_name = item.company_name // [新增]
|
||||
form.material_name = item.name
|
||||
form.spec_model = item.spec
|
||||
form.material_type = item.type
|
||||
@ -552,6 +658,28 @@ const fetchData = async () => {
|
||||
} finally { loading.value = false }
|
||||
}
|
||||
|
||||
const fetchOptions = async () => {
|
||||
try {
|
||||
const res: any = await getFilterOptions()
|
||||
if (res.code === 200) {
|
||||
categoryOptions.value = res.data.categories
|
||||
typeOptions.value = res.data.types
|
||||
companyOptions.value = res.data.companies // [新增]
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Fetch options failed", e)
|
||||
}
|
||||
}
|
||||
|
||||
const resetQuery = () => {
|
||||
queryParams.keyword = ''
|
||||
queryParams.category = ''
|
||||
queryParams.material_type = ''
|
||||
queryParams.company = ''
|
||||
queryParams.page = 1
|
||||
fetchData()
|
||||
}
|
||||
|
||||
const handleCreate = () => {
|
||||
dialogStatus.value = 'create'
|
||||
resetForm()
|
||||
@ -582,7 +710,7 @@ const handleUpdate = (row: any) => {
|
||||
inspectionFileList.value = iReports.filter(r => !isExternalLink(r)).map(url => ({ name: url.split('/').pop(), url: getImageUrl(url) }))
|
||||
const iLinks = iReports.filter(r => isExternalLink(r))
|
||||
inspection_url.value = iLinks.length > 0 ? iLinks[0] : ''
|
||||
materialOptions.value = [{ id: row.base_id, name: row.material_name, spec: row.spec_model, category: row.category, isHistory: false }]
|
||||
materialOptions.value = [{ id: row.base_id, name: row.material_name, spec: row.spec_model, category: row.category, company_name: row.company_name, isHistory: false }]
|
||||
// 回显BOM
|
||||
if (form.bom_code) {
|
||||
bomOptions.value = [{ bom_no: form.bom_code, version: form.bom_version }]
|
||||
@ -705,7 +833,10 @@ const resetForm = () => {
|
||||
const getStatusType = (s:string) => ({'在库':'success','出库':'info','借库':'warning','损耗':'danger'}[s]||'warning')
|
||||
const getQualityType = (s:string) => ({'合格':'success','不合格':'danger','待检':'info'}[s]||'info')
|
||||
const formatMoney = (val:any) => isNaN(Number(val)) ? '-' : `¥ ${Number(val).toFixed(2)}`
|
||||
onMounted(() => fetchData())
|
||||
onMounted(() => {
|
||||
fetchData()
|
||||
fetchOptions()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@ -747,4 +878,31 @@ onMounted(() => fetchData())
|
||||
.camera-card:hover { border-color: #409EFF; color: #409EFF; }
|
||||
.camera-card .text { font-size: 12px; margin-top: 5px; }
|
||||
.camera-card .el-icon { font-size: 24px; }
|
||||
|
||||
/* [重点] 下拉框 Flex 布局 */
|
||||
.option-item { display: flex; align-items: center; padding: 8px 0; width: 100%; }
|
||||
.opt-main { flex: 1; min-width: 0; margin-right: 10px; }
|
||||
.opt-name { font-weight: 600; font-size: 14px; color: #333; display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.opt-meta { width: 100px; text-align: right; flex-shrink: 0; margin-right: 10px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.opt-spec { color: #999; font-size: 12px; }
|
||||
.opt-tags { display: flex; gap: 5px; flex-shrink: 0; }
|
||||
.company-tag { font-weight: bold; }
|
||||
|
||||
/* [新增] 修复 filter-item-select/input 样式 */
|
||||
.filter-item-select { /* 宽度已在行内样式控制 */ }
|
||||
.filter-item-input { /* 宽度已在行内样式控制 */ }
|
||||
.action-btn { font-weight: 500; }
|
||||
|
||||
/* [新增] 修复弹窗最小高度 */
|
||||
.dialog-scroll-container { min-height: 450px; }
|
||||
|
||||
/* [新增] 纯文本样式 */
|
||||
.is-text-view :deep(.el-input__wrapper) { box-shadow: none !important; background-color: transparent !important; border-bottom: 1px dashed #dcdfe6; border-radius: 0; padding-left: 0; }
|
||||
.is-text-view :deep(.el-input__inner) { color: #303133; font-weight: 600; font-size: 14px; cursor: text; }
|
||||
</style>
|
||||
|
||||
<style>
|
||||
.long-dropdown { width: 580px !important; }
|
||||
.long-dropdown .el-select-dropdown__wrap { max-height: 320px !important; }
|
||||
.long-dropdown .el-input__suffix { z-index: 10; }
|
||||
</style>
|
||||
@ -1,17 +1,36 @@
|
||||
<template>
|
||||
<div class="semi-module">
|
||||
<div class="header-tools">
|
||||
<div class="left-tools" style="display: flex; align-items: center; gap: 10px; flex-wrap: wrap;">
|
||||
<div class="left-tools">
|
||||
|
||||
<el-select
|
||||
v-model="queryParams.company"
|
||||
placeholder="所属公司"
|
||||
class="filter-item-select"
|
||||
clearable
|
||||
filterable
|
||||
@change="fetchData"
|
||||
style="width: 160px;"
|
||||
>
|
||||
<el-option v-for="item in companyOptions" :key="item" :label="item" :value="item" />
|
||||
</el-select>
|
||||
|
||||
<el-input
|
||||
v-model="queryParams.keyword"
|
||||
placeholder="请输入名称或规格"
|
||||
class="filter-item-input"
|
||||
clearable
|
||||
@clear="fetchData"
|
||||
@keyup.enter="fetchData"
|
||||
style="width: 240px;"
|
||||
/>
|
||||
>
|
||||
<template #prefix><el-icon><Search /></el-icon></template>
|
||||
</el-input>
|
||||
|
||||
<el-select
|
||||
v-model="queryParams.category"
|
||||
placeholder="类别"
|
||||
class="filter-item-select"
|
||||
clearable
|
||||
filterable
|
||||
@change="fetchData"
|
||||
@ -19,9 +38,11 @@
|
||||
>
|
||||
<el-option v-for="item in categoryOptions" :key="item" :label="item" :value="item" />
|
||||
</el-select>
|
||||
|
||||
<el-select
|
||||
v-model="queryParams.material_type"
|
||||
placeholder="类型"
|
||||
class="filter-item-select"
|
||||
clearable
|
||||
filterable
|
||||
@change="fetchData"
|
||||
@ -29,14 +50,16 @@
|
||||
>
|
||||
<el-option v-for="item in typeOptions" :key="item" :label="item" :value="item" />
|
||||
</el-select>
|
||||
<el-button type="primary" plain @click="fetchData">搜索</el-button>
|
||||
<el-button @click="resetQuery">重置</el-button>
|
||||
|
||||
<el-button type="primary" plain class="search-btn" @click="fetchData">搜索</el-button>
|
||||
<el-button class="reset-btn" @click="resetQuery">重置</el-button>
|
||||
|
||||
<el-select
|
||||
v-model="queryParams.statuses"
|
||||
multiple
|
||||
collapse-tags
|
||||
placeholder="状态筛选"
|
||||
style="width: 220px;"
|
||||
style="width: 200px; margin-left: 10px;"
|
||||
@change="fetchData"
|
||||
>
|
||||
<el-option label="在库" value="在库" />
|
||||
@ -46,12 +69,12 @@
|
||||
</div>
|
||||
|
||||
<div class="right-tools">
|
||||
<el-button type="primary" :icon="Plus" @click="handleCreate" class="action-btn">半成品入库登记</el-button>
|
||||
<el-button :icon="Refresh" @click="fetchData" class="action-btn">刷新</el-button>
|
||||
<el-button type="primary" :icon="Plus" @click="handleCreate" class="add-btn">半成品入库</el-button>
|
||||
<el-button :icon="Refresh" circle @click="fetchData" class="circle-btn" />
|
||||
|
||||
<el-popover placement="bottom-end" title="列配置" :width="500" trigger="click">
|
||||
<template #reference>
|
||||
<el-button :icon="Setting" class="action-btn">表头</el-button>
|
||||
<el-button :icon="Setting" circle class="circle-btn" />
|
||||
</template>
|
||||
<el-checkbox-group v-model="visibleColumnProps" class="column-selector">
|
||||
<div class="col-group-title">基础信息</div>
|
||||
@ -95,6 +118,11 @@
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<template #default="scope" v-else-if="col.prop === 'company_name'">
|
||||
<el-tag v-if="scope.row.company_name" type="info" effect="plain" size="small" style="font-weight: bold;">{{ scope.row.company_name }}</el-tag>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
|
||||
<template #default="scope" v-else-if="col.prop === 'sn_bn'">
|
||||
<div v-if="scope.row.serial_number" class="id-cell">
|
||||
<span class="prefix-tag sn">SN</span>
|
||||
@ -195,35 +223,41 @@
|
||||
top="5vh"
|
||||
destroy-on-close
|
||||
:close-on-click-modal="false"
|
||||
class="stylish-dialog"
|
||||
class="stylish-dialog compact-layout"
|
||||
>
|
||||
<div class="dialog-scroll-container">
|
||||
<el-form :model="form" label-width="100px" ref="formRef" :rules="rules" size="default" class="stylish-form">
|
||||
|
||||
<div class="form-card basic-card">
|
||||
<div class="card-title">
|
||||
<el-icon class="icon"><Box/></el-icon>
|
||||
<span>1. 基础信息</span>
|
||||
<div style="display: flex; align-items: center;">
|
||||
<el-icon class="icon"><Box/></el-icon>
|
||||
<span>1. 基础信息</span>
|
||||
</div>
|
||||
<span class="sub-title" v-if="dialogStatus === 'create'"> (请先搜索选择半成品物料)</span>
|
||||
</div>
|
||||
|
||||
<div class="card-content">
|
||||
<el-row :gutter="24" v-if="dialogStatus === 'create'" style="margin-bottom: 20px;">
|
||||
<el-col :span="10">
|
||||
<el-form-item label="物料搜索" prop="base_id">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="物料搜索" prop="base_id" class="highlight-label">
|
||||
<el-select
|
||||
v-model="form.base_id"
|
||||
filterable
|
||||
remote
|
||||
reserve-keyword
|
||||
placeholder="输入名称或规格..."
|
||||
clearable
|
||||
placeholder="请输入名称或规格进行检索..."
|
||||
:remote-method="handleSearchMaterial"
|
||||
@visible-change="handleMaterialDropdownVisible"
|
||||
:loading="searchLoading"
|
||||
style="width: 100%"
|
||||
@change="onMaterialSelected"
|
||||
default-first-option
|
||||
v-loadmore="loadMoreMaterials"
|
||||
popper-class="long-dropdown"
|
||||
>
|
||||
<template #prefix><el-icon><Search /></el-icon></template>
|
||||
<el-option
|
||||
v-for="item in materialOptions"
|
||||
:key="item.id"
|
||||
@ -231,29 +265,40 @@
|
||||
:value="item.id"
|
||||
>
|
||||
<div class="option-item">
|
||||
<span class="opt-name">{{ item.name }}</span>
|
||||
<span class="opt-spec">{{ item.spec }}</span>
|
||||
<el-tag v-if="item.isHistory" size="small" type="info" effect="plain">历史</el-tag>
|
||||
<el-tag v-else size="small" type="success" effect="plain">系统</el-tag>
|
||||
<div class="opt-main">
|
||||
<span class="opt-name" :title="item.name">{{ item.name }}</span>
|
||||
</div>
|
||||
<div class="opt-meta">
|
||||
<span class="opt-spec" :title="item.spec">{{ item.spec || '-' }}</span>
|
||||
</div>
|
||||
<div class="opt-tags">
|
||||
<el-tag size="small" type="info" effect="light" class="company-tag">{{ item.company_name }}</el-tag>
|
||||
<el-tag v-if="item.isHistory" size="small" type="info" effect="plain">历史</el-tag>
|
||||
<el-tag v-else size="small" type="success" effect="plain">系统</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
</el-option>
|
||||
<div v-if="loadingMore" style="text-align: center; color: #999; font-size: 12px; padding: 8px; background: #f9f9f9;">
|
||||
<el-icon class="is-loading"><Refresh /></el-icon> 加载更多中...
|
||||
</div>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="14" style="display: flex; align-items: center;">
|
||||
<span class="search-tip">
|
||||
<el-icon><InfoFilled/></el-icon> 未输入时展示最新物料;输入关键词进行精确搜索。
|
||||
</span>
|
||||
<el-col :span="12" style="display: flex; align-items: center;">
|
||||
<span class="search-tip">
|
||||
<el-icon><InfoFilled/></el-icon> 支持名称、规格型号、公司名称模糊搜索
|
||||
</span>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<div class="read-only-grid">
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="8"><el-form-item label="名称"><el-input v-model="form.material_name" disabled class="is-text-view"/></el-form-item></el-col>
|
||||
<el-col :span="8"><el-form-item label="规格型号"><el-input v-model="form.spec_model" disabled class="is-text-view"/></el-form-item></el-col>
|
||||
<el-col :span="8"><el-form-item label="单位"><el-input v-model="form.unit" disabled class="is-text-view"/></el-form-item></el-col>
|
||||
<el-col :span="8"><el-form-item label="类别"><el-input v-model="form.category" disabled class="is-text-view"/></el-form-item></el-col>
|
||||
<el-col :span="8"><el-form-item label="类型"><el-input v-model="form.material_type" disabled class="is-text-view"/></el-form-item></el-col>
|
||||
<el-col :span="8"><el-form-item label="所属公司"><el-input v-model="form.company_name" readonly class="is-text-view"/></el-form-item></el-col>
|
||||
<el-col :span="8"><el-form-item label="名称"><el-input v-model="form.material_name" readonly class="is-text-view"/></el-form-item></el-col>
|
||||
<el-col :span="8"><el-form-item label="规格型号"><el-input v-model="form.spec_model" readonly class="is-text-view"/></el-form-item></el-col>
|
||||
<el-col :span="8"><el-form-item label="单位"><el-input v-model="form.unit" readonly class="is-text-view"/></el-form-item></el-col>
|
||||
<el-col :span="8"><el-form-item label="类别"><el-input v-model="form.category" readonly class="is-text-view"/></el-form-item></el-col>
|
||||
<el-col :span="8"><el-form-item label="类型"><el-input v-model="form.material_type" readonly class="is-text-view"/></el-form-item></el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
@ -269,8 +314,8 @@
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="6"><el-form-item label="编码/SKU" prop="sku"><el-input v-model="form.sku" placeholder="系统自动生成" disabled/></el-form-item></el-col>
|
||||
<el-col :span="6"><el-form-item label="入库日期" prop="in_date"><el-date-picker v-model="form.in_date" type="date" value-format="YYYY-MM-DD" style="width:100%" disabled/></el-form-item></el-col>
|
||||
<el-col :span="6"><el-form-item label="条码" prop="barcode"><el-input v-model="form.barcode" placeholder="扫描条码"/></el-form-item></el-col>
|
||||
<el-col :span="6"><el-form-item label="库位" prop="warehouse_location"><el-input v-model="form.warehouse_location" placeholder="例如: B-01-01"/></el-form-item></el-col>
|
||||
<el-col :span="6"><el-form-item label="条码" prop="barcode"><el-input v-model="form.barcode" placeholder="扫描条码" clearable/></el-form-item></el-col>
|
||||
<el-col :span="6"><el-form-item label="库位" prop="warehouse_location"><el-input v-model="form.warehouse_location" placeholder="例如: B-01-01" clearable/></el-form-item></el-col>
|
||||
</el-row>
|
||||
|
||||
<div class="identity-panel">
|
||||
@ -366,13 +411,15 @@
|
||||
|
||||
<div class="form-card production-card">
|
||||
<div class="card-title">
|
||||
<el-icon class="icon"><Setting/></el-icon>
|
||||
<span>3. 生产与成本信息</span>
|
||||
<div style="display: flex; align-items: center;">
|
||||
<el-icon class="icon"><Setting/></el-icon>
|
||||
<span>3. 生产与成本信息</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<div class="divider-text">生产任务信息</div>
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="8"><el-form-item label="工单号"><el-input v-model="form.work_order_code" placeholder="WO-xxx"/></el-form-item></el-col>
|
||||
<el-col :span="8"><el-form-item label="工单号"><el-input v-model="form.work_order_code" placeholder="WO-xxx" clearable/></el-form-item></el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="BOM编号">
|
||||
@ -440,7 +487,7 @@
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="visible = false" size="large">取消</el-button>
|
||||
<el-button type="primary" :loading="submitting" @click="submitForm" size="large" class="confirm-btn">
|
||||
{{ dialogStatus === 'create' ? '确认入库并打印' : '保存修改' }}
|
||||
{{ dialogStatus === 'create' ? '提交并打印' : '保存修改' }}
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
@ -480,13 +527,35 @@ import {
|
||||
updateSemiInbound,
|
||||
deleteSemiInbound,
|
||||
searchMaterialBase,
|
||||
searchBom, // [新增]
|
||||
searchBom,
|
||||
getFilterOptions
|
||||
} from '@/api/inbound/semi'
|
||||
import { uploadFile, deleteFile } from '@/api/inbound/buy'
|
||||
import WebRtcCamera from '@/components/Camera/WebRtcCamera.vue'
|
||||
import {getLabelPreview, executePrint} from '@/api/common/print'
|
||||
|
||||
// ------------------------------------
|
||||
// 自定义指令:v-loadmore (适配 Teleport 到 Body 的下拉框)
|
||||
// ------------------------------------
|
||||
const vLoadmore = {
|
||||
mounted(el: any, binding: any) {
|
||||
const checkAndBind = () => {
|
||||
const dropDownWrap = document.querySelector('.long-dropdown .el-select-dropdown__wrap')
|
||||
if (dropDownWrap && !dropDownWrap.getAttribute('data-loadmore-bound')) {
|
||||
dropDownWrap.setAttribute('data-loadmore-bound', 'true')
|
||||
dropDownWrap.addEventListener('scroll', function (this: any) {
|
||||
const condition = this.scrollHeight - this.scrollTop <= this.clientHeight + 1
|
||||
if (condition) {
|
||||
binding.value()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
setTimeout(checkAndBind, 500)
|
||||
el.addEventListener('click', () => setTimeout(checkAndBind, 300))
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------
|
||||
// 状态与变量
|
||||
// ------------------------------------
|
||||
@ -494,14 +563,20 @@ const loading = ref(false)
|
||||
const submitting = ref(false)
|
||||
const visible = ref(false)
|
||||
const searchLoading = ref(false)
|
||||
const loadingMore = ref(false)
|
||||
const dialogStatus = ref<'create' | 'update'>('create')
|
||||
const tableData = ref([])
|
||||
const total = ref(0)
|
||||
const formRef = ref()
|
||||
const queryParams = reactive({ page: 1, pageSize: 100, keyword: '', category: '', material_type: '', statuses: ['在库', '借库'] })
|
||||
const queryParams = reactive({ page: 1, pageSize: 100, keyword: '', category: '', material_type: '', statuses: ['在库', '借库'], company: '' })
|
||||
const categoryOptions = ref<string[]>([])
|
||||
const typeOptions = ref<string[]>([])
|
||||
const companyOptions = ref<string[]>([]) // [新增]
|
||||
const materialOptions = ref<any[]>([])
|
||||
const searchPage = ref(1)
|
||||
const searchKeyword = ref('')
|
||||
const hasNextPage = ref(true)
|
||||
let searchTimer: any = null
|
||||
|
||||
// BOM 搜索相关
|
||||
const bomSearchLoading = ref(false)
|
||||
@ -529,6 +604,7 @@ const modeLocked = ref(false)
|
||||
|
||||
// 列定义
|
||||
const baseColumns = [
|
||||
{prop: 'company_name', label: '所属公司'}, // [新增]
|
||||
{prop: 'material_name', label: '名称'},
|
||||
{prop: 'category', label: '类别'},
|
||||
{prop: 'material_type', label: '类型'},
|
||||
@ -564,15 +640,13 @@ const stockColumns = [
|
||||
]
|
||||
const allColumns = [...baseColumns, ...stockColumns]
|
||||
|
||||
const defaultColumns = ['material_name', 'spec_model', 'unit', 'inbound_date', 'sn_bn', 'status', 'quality_status', 'bom_code', 'work_order_code', 'qty_stock', 'qty_available', 'unit_total_cost', 'arrival_photo', 'quality_report_link']
|
||||
const defaultColumns = ['company_name', 'material_name', 'spec_model', 'unit', 'inbound_date', 'sn_bn', 'status', 'quality_status', 'bom_code', 'work_order_code', 'qty_stock', 'qty_available', 'unit_total_cost', 'arrival_photo', 'quality_report_link']
|
||||
const visibleColumnProps = ref(defaultColumns)
|
||||
|
||||
const form = reactive({
|
||||
id: undefined, base_id: undefined as number | undefined, material_name: '', spec_model: '', category: '', unit: '', material_type: '',
|
||||
sku: '', barcode: '', in_date: '', serial_number: '', batch_number: '', status: '在库', quality_status: '合格',
|
||||
in_quantity: 1, stock_quantity: 1, available_quantity: 1, warehouse_location: '',
|
||||
bom_code: '', bom_version: '', work_order_code: '', raw_material_cost: 0, manual_cost: 0, unit_total_cost: 0,
|
||||
production_manager: '', production_time_range: [] as string[], arrival_photo: [] as string[], quality_report_link: [] as string[], detail_link: ''
|
||||
id: undefined, base_id: undefined as number | undefined,
|
||||
company_name: '', // [新增]
|
||||
material_name: '', spec_model: '', category: '', unit: '', material_type: '', sku: '', barcode: '', in_date: '', serial_number: '', batch_number: '', status: '在库', quality_status: '合格', in_quantity: 1, stock_quantity: 1, available_quantity: 1, warehouse_location: '', bom_code: '', bom_version: '', work_order_code: '', raw_material_cost: 0, manual_cost: 0, unit_total_cost: 0, production_manager: '', production_time_range: [] as string[], arrival_photo: [] as string[], quality_report_link: [] as string[], detail_link: ''
|
||||
})
|
||||
|
||||
// ------------------------------------
|
||||
@ -609,18 +683,53 @@ const handleManagerSelect = (item: any) => {
|
||||
// ------------------------------------
|
||||
// Material Search (Matches Buy.vue)
|
||||
// ------------------------------------
|
||||
const handleMaterialDropdownVisible = (visible: boolean) => { if (visible && materialOptions.value.length === 0) handleSearchMaterial('') }
|
||||
const handleMaterialDropdownVisible = (visible: boolean) => { if (visible && materialOptions.value.length === 0) handleSearchMaterialDebounced('') }
|
||||
|
||||
const handleSearchMaterialDebounced = (query: string) => {
|
||||
if (searchTimer) clearTimeout(searchTimer)
|
||||
searchTimer = setTimeout(() => {
|
||||
handleSearchMaterial(query)
|
||||
}, 300)
|
||||
}
|
||||
|
||||
const handleSearchMaterial = async (query: string) => {
|
||||
searchLoading.value = true
|
||||
searchKeyword.value = query
|
||||
searchPage.value = 1
|
||||
materialOptions.value = []
|
||||
|
||||
try {
|
||||
const res: any = await searchMaterialBase(query)
|
||||
const res: any = await searchMaterialBase(query, 1)
|
||||
const apiResults = (res.data || []).map((i: any) => ({...i, isHistory: false}))
|
||||
materialOptions.value = apiResults
|
||||
hasNextPage.value = res.has_next
|
||||
} finally { searchLoading.value = false }
|
||||
}
|
||||
|
||||
const loadMoreMaterials = async () => {
|
||||
if (searchLoading.value || loadingMore.value || !hasNextPage.value) return
|
||||
loadingMore.value = true
|
||||
searchPage.value += 1
|
||||
try {
|
||||
const res: any = await searchMaterialBase(searchKeyword.value, searchPage.value)
|
||||
if (res.data && res.data.length > 0) {
|
||||
const newItems = res.data.map((i: any) => ({...i, isHistory: false}))
|
||||
materialOptions.value.push(...newItems)
|
||||
hasNextPage.value = res.has_next
|
||||
} else {
|
||||
hasNextPage.value = false
|
||||
}
|
||||
} catch (e) {
|
||||
searchPage.value -= 1
|
||||
} finally {
|
||||
loadingMore.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const onMaterialSelected = (val: number) => {
|
||||
const item = materialOptions.value.find(i => i.id === val)
|
||||
if (item) {
|
||||
form.company_name = item.company_name // [新增]
|
||||
form.material_name = item.name
|
||||
form.spec_model = item.spec
|
||||
form.category = item.category
|
||||
@ -699,6 +808,7 @@ const fetchOptions = async () => {
|
||||
if (res.code === 200) {
|
||||
categoryOptions.value = res.data.categories
|
||||
typeOptions.value = res.data.types
|
||||
companyOptions.value = res.data.companies // [新增]
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Fetch options failed', e)
|
||||
@ -709,6 +819,7 @@ const resetQuery = () => {
|
||||
queryParams.keyword = ''
|
||||
queryParams.category = ''
|
||||
queryParams.material_type = ''
|
||||
queryParams.company = ''
|
||||
queryParams.page = 1
|
||||
fetchData()
|
||||
}
|
||||
@ -729,7 +840,9 @@ const handleUpdate = (row: any) => {
|
||||
resetForm()
|
||||
modeLocked.value = true
|
||||
Object.assign(form, {
|
||||
id: row.id, base_id: row.base_id, material_name: row.material_name, spec_model: row.spec_model, category: row.category,
|
||||
id: row.id, base_id: row.base_id,
|
||||
company_name: row.company_name, // [新增]
|
||||
material_name: row.material_name, spec_model: row.spec_model, category: row.category,
|
||||
unit: row.unit, material_type: row.material_type, sku: row.sku, barcode: row.barcode, in_date: row.inbound_date,
|
||||
warehouse_location: row.warehouse_loc, status: row.status, quality_status: row.quality_status,
|
||||
in_quantity: Number(row.qty_inbound), stock_quantity: Number(row.qty_stock), available_quantity: Number(row.qty_available),
|
||||
@ -748,7 +861,7 @@ const handleUpdate = (row: any) => {
|
||||
quality_report_url.value = reportLinks.length > 0 ? reportLinks[0] : ''
|
||||
if (row.serial_number) { entryMode.value = 'serial'; form.serial_number = row.serial_number; form.batch_number = '' }
|
||||
else { entryMode.value = 'batch'; form.batch_number = row.batch_number; form.serial_number = '' }
|
||||
materialOptions.value = [{ id: row.base_id, name: row.material_name, spec: row.spec_model, category: row.category, isHistory: false }]
|
||||
materialOptions.value = [{ id: row.base_id, name: row.material_name, spec: row.spec_model, category: row.category, company_name: row.company_name, isHistory: false }]
|
||||
// 回显BOM,如果存在
|
||||
if (form.bom_code) {
|
||||
bomOptions.value = [{ bom_no: form.bom_code, version: form.bom_version }]
|
||||
@ -862,7 +975,10 @@ const handlePrint = async (row: any) => {
|
||||
const confirmPrint = async () => { printing.value = true; try { await executePrint(currentPrintData.value); ElMessage.success('指令已发送'); printVisible.value = false } catch (e: any) { ElMessage.error(e.msg || '打印失败') } finally { printing.value = false } }
|
||||
const resetForm = () => {
|
||||
materialOptions.value = []; bomOptions.value = []; arrivalFileList.value = []; reportFileList.value = []; quality_report_url.value = ''
|
||||
Object.assign(form, { id: undefined, base_id: undefined, material_name: '', spec_model: '', category: '', unit: '', material_type: '', sku: '', barcode: '', in_date: '', serial_number: '', batch_number: '', status: '在库', quality_status: '合格', in_quantity: 1, stock_quantity: 1, available_quantity: 1, warehouse_location: '', bom_code: '', bom_version: '', work_order_code: '', raw_material_cost: 0, manual_cost: 0, unit_total_cost: 0, production_manager: '', production_time_range: [], arrival_photo: [], quality_report_link: [], detail_link: '' })
|
||||
Object.assign(form, {
|
||||
id: undefined, base_id: undefined,
|
||||
company_name: '', // [新增]
|
||||
material_name: '', spec_model: '', category: '', unit: '', material_type: '', sku: '', barcode: '', in_date: '', serial_number: '', batch_number: '', status: '在库', quality_status: '合格', in_quantity: 1, stock_quantity: 1, available_quantity: 1, warehouse_location: '', bom_code: '', bom_version: '', work_order_code: '', raw_material_cost: 0, manual_cost: 0, unit_total_cost: 0, production_manager: '', production_time_range: [], arrival_photo: [], quality_report_link: [], detail_link: '' })
|
||||
}
|
||||
const getStatusType = (status: string) => { const map: any = { '在库': 'success', '出库': 'info', '借库': 'warning', '损耗': 'danger' }; return map[status] || 'warning' }
|
||||
const getQualityType = (status: string) => { const map: any = { '合格': 'success', '不合格': 'danger', '待检': 'info', '返修中': 'warning' }; return map[status] || 'info' }
|
||||
@ -889,7 +1005,10 @@ onMounted(() => {
|
||||
.avail-num { font-weight: bold; color: #67C23A; font-size: 15px; }
|
||||
.id-cell { display: flex; align-items: center; }
|
||||
.id-text { font-family: monospace; color: #606266; }
|
||||
.stylish-form .form-card { background: #fff; border-radius: 8px; border: 1px solid #e4e7ed; margin-bottom: 20px; overflow: hidden; }
|
||||
/* [修改] 增加 min-height */
|
||||
.dialog-scroll-container { padding: 20px; max-height: 70vh; overflow-y: auto; overflow-x: hidden; min-height: 450px; }
|
||||
|
||||
.stylish-form .form-card { background: #fff; border-radius: 8px; border: 1px solid #e4e7ed; margin-bottom: 20px; }
|
||||
.card-title { background: #fcfcfc; padding: 12px 20px; border-bottom: 1px solid #ebeef5; font-weight: 600; font-size: 15px; color: #303133; display: flex; align-items: center; }
|
||||
.card-title .icon { margin-right: 8px; font-size: 18px; color: #409EFF; }
|
||||
.card-title .sub-title { font-size: 12px; color: #909399; font-weight: normal; margin-left: 10px; }
|
||||
@ -908,13 +1027,19 @@ onMounted(() => {
|
||||
.divider-text::before { margin-right: 15px; }
|
||||
.divider-text::after { margin-left: 15px; }
|
||||
.dialog-footer { display: flex; justify-content: flex-end; gap: 15px; margin-top: 20px; padding: 20px; border-top: 1px solid #ebeef5; }
|
||||
.option-item { display: flex; justify-content: space-between; width: 100%; align-items: center; }
|
||||
.opt-name { font-weight: bold; }
|
||||
.opt-spec { color: #8492a6; font-size: 13px; margin-right: 10px; }
|
||||
.is-text-view :deep(.el-input__wrapper) { box-shadow: none !important; background-color: #f5f7fa; border-bottom: 1px solid #dcdfe6; border-radius: 0; padding-left: 0; }
|
||||
.is-text-view :deep(.el-input__inner) { color: #606266; font-weight: 500; }
|
||||
|
||||
.filter-item-select { /* 宽度已在行内样式控制 */ }
|
||||
.filter-item-input { /* 宽度已在行内样式控制 */ }
|
||||
.search-btn { background-color: #E6F1FC; border-color: #A3D0FD; color: #409EFF; }
|
||||
.search-btn:hover { background-color: #409EFF; border-color: #409EFF; color: #fff; }
|
||||
.reset-btn { background-color: #fff; border: 1px solid #dcdfe6; }
|
||||
.reset-btn:hover { border-color: #c0c4cc; color: #606266; }
|
||||
|
||||
/* [优化] 纯文本样式 */
|
||||
.is-text-view :deep(.el-input__wrapper) { box-shadow: none !important; background-color: transparent !important; border-bottom: 1px dashed #dcdfe6; border-radius: 0; padding-left: 0; }
|
||||
.is-text-view :deep(.el-input__inner) { color: #303133; font-weight: 600; font-size: 14px; cursor: text; }
|
||||
|
||||
.search-tip { color: #909399; font-size: 12px; margin-left: 10px; display: flex; align-items: center; gap: 4px; }
|
||||
.dialog-scroll-container { padding: 20px; max-height: 70vh; overflow-y: auto; }
|
||||
.upload-container { display: flex; flex-wrap: wrap; gap: 8px; }
|
||||
:deep(.el-upload--picture-card) { width: 100px; height: 100px; line-height: 100px; }
|
||||
:deep(.el-upload-list--picture-card .el-upload-list__item) { width: 100px; height: 100px; }
|
||||
@ -922,4 +1047,19 @@ onMounted(() => {
|
||||
.camera-card:hover { border-color: #409EFF; color: #409EFF; }
|
||||
.camera-card .text { font-size: 12px; margin-top: 5px; }
|
||||
.camera-card .el-icon { font-size: 24px; }
|
||||
|
||||
/* [重点] 下拉框 Flex 布局 */
|
||||
.option-item { display: flex; align-items: center; padding: 8px 0; width: 100%; }
|
||||
.opt-main { flex: 1; min-width: 0; margin-right: 10px; }
|
||||
.opt-name { font-weight: 600; font-size: 14px; color: #333; display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.opt-meta { width: 100px; text-align: right; flex-shrink: 0; margin-right: 10px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.opt-spec { color: #999; font-size: 12px; }
|
||||
.opt-tags { display: flex; gap: 5px; flex-shrink: 0; }
|
||||
.company-tag { font-weight: bold; }
|
||||
</style>
|
||||
|
||||
<style>
|
||||
.long-dropdown { width: 580px !important; }
|
||||
.long-dropdown .el-select-dropdown__wrap { max-height: 320px !important; }
|
||||
.long-dropdown .el-input__suffix { z-index: 10; }
|
||||
</style>
|
||||
Reference in New Issue
Block a user