|
@@ -1,103 +1,157 @@
|
|
|
<template>
|
|
<template>
|
|
|
<el-drawer
|
|
<el-drawer
|
|
|
- title="物料详情"
|
|
|
|
|
:append-to-body="true"
|
|
:append-to-body="true"
|
|
|
:model-value="modelValue"
|
|
:model-value="modelValue"
|
|
|
- @update:model-value="$emit('update:modelValue', $event)"
|
|
|
|
|
:show-close="false"
|
|
:show-close="false"
|
|
|
direction="rtl"
|
|
direction="rtl"
|
|
|
:size="computedSize"
|
|
:size="computedSize"
|
|
|
:before-close="handleClose"
|
|
:before-close="handleClose"
|
|
|
- >
|
|
|
|
|
|
|
+ class="material-detail-drawer"
|
|
|
|
|
+ @update:model-value="$emit('update:modelValue', $event)">
|
|
|
|
|
+ <template #header>
|
|
|
|
|
+ <div class="drawer-header">
|
|
|
|
|
+ <div class="drawer-header__main">
|
|
|
|
|
+ <div class="drawer-header__icon">
|
|
|
|
|
+ <Icon icon="ep:goods" :size="22" />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <div class="drawer-title">物料详情</div>
|
|
|
|
|
+ <div class="drawer-subtitle">查看并维护当前 BOM 节点关联的物料数量</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <el-button circle size="default" @click="handleClose">
|
|
|
|
|
+ <Icon icon="ep:close" />
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+
|
|
|
<template v-if="nodeId">
|
|
<template v-if="nodeId">
|
|
|
- <div v-loading="loading" style="height: 100%">
|
|
|
|
|
|
|
+ <div v-loading="loading" class="drawer-body">
|
|
|
|
|
+ <section class="info-card">
|
|
|
|
|
+ <div class="info-card__header">
|
|
|
|
|
+ <div class="info-card__title">
|
|
|
|
|
+ <span class="info-card__marker"></span>
|
|
|
|
|
+ <span>BOM 信息</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
|
|
|
- <div class="info-header">
|
|
|
|
|
- <div class="info-item">
|
|
|
|
|
- <span class="info-label">设备分类:</span>
|
|
|
|
|
- <span class="info-value">{{ rowInfo.deviceCategoryName }}</span>
|
|
|
|
|
|
|
+ <div class="info-card__body">
|
|
|
|
|
+ <div class="detail-grid">
|
|
|
|
|
+ <div class="detail-item">
|
|
|
|
|
+ <div class="detail-item__label">设备分类</div>
|
|
|
|
|
+ <div class="detail-item__value">{{ rowInfo.deviceCategoryName }}</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="detail-item">
|
|
|
|
|
+ <div class="detail-item__label">BOM节点</div>
|
|
|
|
|
+ <div class="detail-item__value">{{ rowInfo.bomNodeName }}</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
- <div class="separator"></div> <!-- 分隔线 -->
|
|
|
|
|
- <div class="info-item">
|
|
|
|
|
- <span class="info-label">BOM节点:</span>
|
|
|
|
|
- <span class="info-value">{{ rowInfo.bomNodeName }}</span>
|
|
|
|
|
|
|
+ </section>
|
|
|
|
|
+
|
|
|
|
|
+ <section class="info-card material-card">
|
|
|
|
|
+ <div class="info-card__header">
|
|
|
|
|
+ <div class="info-card__title">
|
|
|
|
|
+ <span class="info-card__marker"></span>
|
|
|
|
|
+ <span>关联物料</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <span class="material-total">共 {{ total }} 条</span>
|
|
|
</div>
|
|
</div>
|
|
|
- </div>
|
|
|
|
|
|
|
|
|
|
- <el-table :data="materials" style="width: 100%" fit :row-style="{ height: '38px' }">
|
|
|
|
|
- <el-table-column prop="name" :label="t('workOrderMaterial.materialName')" min-width="150" show-overflow-tooltip/>
|
|
|
|
|
- <el-table-column prop="code" :label="t('workOrderMaterial.materialCode')" min-width="80" />
|
|
|
|
|
- <el-table-column prop="quantity" :label="t('route.quantity')" min-width="70" align="center">
|
|
|
|
|
- <template #default="scope">
|
|
|
|
|
- <el-form
|
|
|
|
|
- :model="scope.row"
|
|
|
|
|
- :rules="quantityRules"
|
|
|
|
|
- ref="quantityFormRef"
|
|
|
|
|
- @submit.prevent
|
|
|
|
|
- >
|
|
|
|
|
- <el-form-item prop="quantity" :error="scope.row.quantityError">
|
|
|
|
|
- <el-input
|
|
|
|
|
- v-model.number="scope.row.quantity"
|
|
|
|
|
- type="number"
|
|
|
|
|
- size="small"
|
|
|
|
|
- placeholder="请输入数量"
|
|
|
|
|
- @blur="clearQuantityError(scope.row)"
|
|
|
|
|
- @keyup.enter="handleUpdate(scope.row)"
|
|
|
|
|
- :class="{ 'error-input': scope.row.quantityError }"
|
|
|
|
|
- />
|
|
|
|
|
- </el-form-item>
|
|
|
|
|
- </el-form>
|
|
|
|
|
- </template>
|
|
|
|
|
- </el-table-column>
|
|
|
|
|
- <el-table-column prop="unit" :label="t('workOrderMaterial.unit')" min-width="50" align="center"/>
|
|
|
|
|
- <el-table-column
|
|
|
|
|
- :label="t('deviceList.createTime')"
|
|
|
|
|
- align="center"
|
|
|
|
|
- prop="createTime"
|
|
|
|
|
- min-width="110"
|
|
|
|
|
- :formatter="dateFormatter"
|
|
|
|
|
- />
|
|
|
|
|
- <el-table-column label="操作" align="right" width="180" fixed="right">
|
|
|
|
|
- <template #default="scope">
|
|
|
|
|
- <el-button
|
|
|
|
|
- size="small"
|
|
|
|
|
- type="success"
|
|
|
|
|
- :loading="scope.row.updating"
|
|
|
|
|
- @click="handleUpdate(scope.row)"
|
|
|
|
|
- >{{ t('iotDevice.update') }}</el-button>
|
|
|
|
|
-
|
|
|
|
|
- <el-button
|
|
|
|
|
- size="small"
|
|
|
|
|
- type="danger"
|
|
|
|
|
- @click="handleDelete(scope.row)"
|
|
|
|
|
- >{{ t('info.delete') }}</el-button>
|
|
|
|
|
- </template>
|
|
|
|
|
- </el-table-column>
|
|
|
|
|
- </el-table>
|
|
|
|
|
- <!-- 分页 -->
|
|
|
|
|
- <Pagination
|
|
|
|
|
- :total="total"
|
|
|
|
|
- v-model:page="queryParams.pageNo"
|
|
|
|
|
- v-model:limit="queryParams.pageSize"
|
|
|
|
|
- @pagination="loadMaterials(props.nodeId)"
|
|
|
|
|
- />
|
|
|
|
|
|
|
+ <div class="info-card__body material-card__body">
|
|
|
|
|
+ <ZmTable
|
|
|
|
|
+ :data="materials"
|
|
|
|
|
+ :loading="loading"
|
|
|
|
|
+ :show-border="true"
|
|
|
|
|
+ settings-cache-key="pms-bom-material-detail"
|
|
|
|
|
+ class="material-table">
|
|
|
|
|
+ <ZmTableColumn
|
|
|
|
|
+ prop="name"
|
|
|
|
|
+ :label="t('workOrderMaterial.materialName')"
|
|
|
|
|
+ min-width="180"
|
|
|
|
|
+ align="left"
|
|
|
|
|
+ fixed="left" />
|
|
|
|
|
+ <ZmTableColumn
|
|
|
|
|
+ prop="code"
|
|
|
|
|
+ :label="t('workOrderMaterial.materialCode')"
|
|
|
|
|
+ min-width="130" />
|
|
|
|
|
+ <ZmTableColumn prop="quantity" :label="t('route.quantity')" min-width="130">
|
|
|
|
|
+ <template #default="{ row }">
|
|
|
|
|
+ <el-form
|
|
|
|
|
+ :model="row"
|
|
|
|
|
+ :rules="quantityRules"
|
|
|
|
|
+ size="default"
|
|
|
|
|
+ class="quantity-form"
|
|
|
|
|
+ @submit.prevent>
|
|
|
|
|
+ <el-form-item prop="quantity" :error="row.quantityError">
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-model.number="row.quantity"
|
|
|
|
|
+ type="number"
|
|
|
|
|
+ size="default"
|
|
|
|
|
+ placeholder="请输入数量"
|
|
|
|
|
+ min="0"
|
|
|
|
|
+ class="quantity-input"
|
|
|
|
|
+ @blur="clearQuantityError(row)"
|
|
|
|
|
+ @keyup.enter="handleUpdate(row)" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-form>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </ZmTableColumn>
|
|
|
|
|
+ <ZmTableColumn prop="unit" :label="t('workOrderMaterial.unit')" min-width="90" />
|
|
|
|
|
+ <ZmTableColumn
|
|
|
|
|
+ :label="t('deviceList.createTime')"
|
|
|
|
|
+ prop="createTime"
|
|
|
|
|
+ min-width="170"
|
|
|
|
|
+ :formatter="dateFormatter" />
|
|
|
|
|
+ <ZmTableColumn label="操作" width="180" fixed="right" action>
|
|
|
|
|
+ <template #default="{ row }">
|
|
|
|
|
+ <div class="table-actions">
|
|
|
|
|
+ <el-button
|
|
|
|
|
+ size="default"
|
|
|
|
|
+ type="primary"
|
|
|
|
|
+ link
|
|
|
|
|
+ :loading="row.updating"
|
|
|
|
|
+ @click="handleUpdate(row)">
|
|
|
|
|
+ <Icon icon="ep:check" class="mr-4px" />修改
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ <el-button size="default" type="danger" link @click="handleDelete(row)">
|
|
|
|
|
+ <Icon icon="ep:delete" class="mr-4px" />删除
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </ZmTableColumn>
|
|
|
|
|
+ </ZmTable>
|
|
|
|
|
+
|
|
|
|
|
+ <Pagination
|
|
|
|
|
+ v-show="total > 0"
|
|
|
|
|
+ :total="total"
|
|
|
|
|
+ v-model:page="queryParams.pageNo"
|
|
|
|
|
+ v-model:limit="queryParams.pageSize"
|
|
|
|
|
+ @pagination="loadMaterials(props.nodeId, false)" />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </section>
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
-
|
|
|
|
|
</el-drawer>
|
|
</el-drawer>
|
|
|
</template>
|
|
</template>
|
|
|
<script setup lang="ts">
|
|
<script setup lang="ts">
|
|
|
|
|
+import { ref, watch } from 'vue'
|
|
|
|
|
+import { ElMessage, type FormRules } from 'element-plus'
|
|
|
|
|
+import { useTableComponents } from '@/components/ZmTable/useTableComponents'
|
|
|
|
|
+import { CommonBomMaterialApi, type CommonBomMaterialVO } from '@/api/pms/commonbommaterial'
|
|
|
|
|
+import { dateFormatter } from '@/utils/formatTime'
|
|
|
|
|
|
|
|
-import { ref, watch, defineOptions, defineEmits } from 'vue'
|
|
|
|
|
-import { ElMessage } from 'element-plus'
|
|
|
|
|
-import * as PmsMaterialApi from '@/api/pms/material'
|
|
|
|
|
-import {CommonBomMaterialApi, CommonBomMaterialVO} from '@/api/pms/commonbommaterial'
|
|
|
|
|
-import {dateFormatter} from "@/utils/formatTime";
|
|
|
|
|
-const drawerVisible = ref<boolean>(false)
|
|
|
|
|
const emit = defineEmits(['update:modelValue', 'add', 'delete', 'refresh'])
|
|
const emit = defineEmits(['update:modelValue', 'add', 'delete', 'refresh'])
|
|
|
const message = useMessage() // 消息弹窗
|
|
const message = useMessage() // 消息弹窗
|
|
|
const { t } = useI18n() // 国际化
|
|
const { t } = useI18n() // 国际化
|
|
|
|
|
|
|
|
|
|
+type MaterialDetailRow = CommonBomMaterialVO & {
|
|
|
|
|
+ updating?: boolean
|
|
|
|
|
+ quantityError?: string
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const { ZmTable, ZmTableColumn } = useTableComponents<MaterialDetailRow>()
|
|
|
|
|
+
|
|
|
defineOptions({
|
|
defineOptions({
|
|
|
name: 'MaterialListDrawer'
|
|
name: 'MaterialListDrawer'
|
|
|
})
|
|
})
|
|
@@ -117,32 +171,36 @@ const quantityRules: FormRules = {
|
|
|
{
|
|
{
|
|
|
validator: (rule, value, callback) => {
|
|
validator: (rule, value, callback) => {
|
|
|
if (isNaN(value)) {
|
|
if (isNaN(value)) {
|
|
|
- callback(new Error('请输入有效数字'));
|
|
|
|
|
|
|
+ callback(new Error('请输入有效数字'))
|
|
|
} else if (value <= 0) {
|
|
} else if (value <= 0) {
|
|
|
- callback(new Error('数量必须大于0'));
|
|
|
|
|
|
|
+ callback(new Error('数量必须大于0'))
|
|
|
} else {
|
|
} else {
|
|
|
- callback();
|
|
|
|
|
|
|
+ callback()
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
trigger: 'blur'
|
|
trigger: 'blur'
|
|
|
}
|
|
}
|
|
|
]
|
|
]
|
|
|
-};
|
|
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
const windowWidth = ref(window.innerWidth)
|
|
const windowWidth = ref(window.innerWidth)
|
|
|
// 动态计算百分比
|
|
// 动态计算百分比
|
|
|
const computedSize = computed(() => {
|
|
const computedSize = computed(() => {
|
|
|
|
|
+ if (windowWidth.value <= 768) return '100%'
|
|
|
return windowWidth.value > 1200 ? '60%' : '80%'
|
|
return windowWidth.value > 1200 ? '60%' : '80%'
|
|
|
})
|
|
})
|
|
|
|
|
+const updateWindowWidth = () => {
|
|
|
|
|
+ windowWidth.value = window.innerWidth
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
const loading = ref(false)
|
|
const loading = ref(false)
|
|
|
const total = ref(0) // 列表的总页数
|
|
const total = ref(0) // 列表的总页数
|
|
|
-const materials = ref([])
|
|
|
|
|
|
|
+const materials = ref<MaterialDetailRow[]>([])
|
|
|
|
|
|
|
|
const props = defineProps({
|
|
const props = defineProps({
|
|
|
modelValue: Boolean,
|
|
modelValue: Boolean,
|
|
|
nodeId: Number,
|
|
nodeId: Number,
|
|
|
- rowInfo: { // 新增props
|
|
|
|
|
|
|
+ rowInfo: {
|
|
|
type: Object,
|
|
type: Object,
|
|
|
default: () => ({
|
|
default: () => ({
|
|
|
deviceCategoryName: '',
|
|
deviceCategoryName: '',
|
|
@@ -152,21 +210,27 @@ const props = defineProps({
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
// 监听bom树节点ID变化
|
|
// 监听bom树节点ID变化
|
|
|
-watch(() => props.nodeId, async (newVal) => {
|
|
|
|
|
- if (newVal) {
|
|
|
|
|
- await loadMaterials(newVal)
|
|
|
|
|
|
|
+watch(
|
|
|
|
|
+ () => props.nodeId,
|
|
|
|
|
+ async (newVal) => {
|
|
|
|
|
+ if (newVal) {
|
|
|
|
|
+ await loadMaterials(newVal)
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
-})
|
|
|
|
|
|
|
+)
|
|
|
|
|
|
|
|
// 加载指定bom节点下的物料数据
|
|
// 加载指定bom节点下的物料数据
|
|
|
-const loadMaterials = async (nodeId) => {
|
|
|
|
|
- queryParams.bomNodeId = nodeId
|
|
|
|
|
- queryParams.pageNo = 1
|
|
|
|
|
|
|
+const loadMaterials = async (nodeId?: number, resetPage = true) => {
|
|
|
|
|
+ if (!nodeId) return
|
|
|
|
|
+ queryParams.bomNodeId = nodeId as any
|
|
|
|
|
+ if (resetPage) {
|
|
|
|
|
+ queryParams.pageNo = 1
|
|
|
|
|
+ }
|
|
|
try {
|
|
try {
|
|
|
loading.value = true
|
|
loading.value = true
|
|
|
// API调用
|
|
// API调用
|
|
|
const data = await CommonBomMaterialApi.getCommonBomMaterialPage(queryParams)
|
|
const data = await CommonBomMaterialApi.getCommonBomMaterialPage(queryParams)
|
|
|
- materials.value = data.list.map(item => ({
|
|
|
|
|
|
|
+ materials.value = data.list.map((item) => ({
|
|
|
...item,
|
|
...item,
|
|
|
updating: false, // 更新状态标记
|
|
updating: false, // 更新状态标记
|
|
|
quantityError: '' // 错误状态标记
|
|
quantityError: '' // 错误状态标记
|
|
@@ -180,30 +244,30 @@ const loadMaterials = async (nodeId) => {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/** 清除数量错误状态 */
|
|
/** 清除数量错误状态 */
|
|
|
-const clearQuantityError = (row: CommonBomMaterialVO) => {
|
|
|
|
|
|
|
+const clearQuantityError = (row: MaterialDetailRow) => {
|
|
|
// 延迟清除错误状态,避免在验证过程中清除
|
|
// 延迟清除错误状态,避免在验证过程中清除
|
|
|
setTimeout(() => {
|
|
setTimeout(() => {
|
|
|
- row.quantityError = '';
|
|
|
|
|
- }, 100);
|
|
|
|
|
|
|
+ row.quantityError = ''
|
|
|
|
|
+ }, 100)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/** 更新物料数据 */
|
|
/** 更新物料数据 */
|
|
|
-const handleUpdate = async (row: CommonBomMaterialVO) => {
|
|
|
|
|
|
|
+const handleUpdate = async (row: MaterialDetailRow) => {
|
|
|
try {
|
|
try {
|
|
|
if (isNaN(row.quantity)) {
|
|
if (isNaN(row.quantity)) {
|
|
|
- row.quantityError = '请输入有效数字';
|
|
|
|
|
- ElMessage.warning('请输入有效的数字');
|
|
|
|
|
- return;
|
|
|
|
|
|
|
+ row.quantityError = '请输入有效数字'
|
|
|
|
|
+ ElMessage.warning('请输入有效的数字')
|
|
|
|
|
+ return
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (row.quantity <= 0) {
|
|
if (row.quantity <= 0) {
|
|
|
- row.quantityError = '数量必须大于0';
|
|
|
|
|
- ElMessage.warning('数量必须大于0');
|
|
|
|
|
- return;
|
|
|
|
|
|
|
+ row.quantityError = '数量必须大于0'
|
|
|
|
|
+ ElMessage.warning('数量必须大于0')
|
|
|
|
|
+ return
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 清除错误状态
|
|
// 清除错误状态
|
|
|
- row.quantityError = '';
|
|
|
|
|
|
|
+ row.quantityError = ''
|
|
|
|
|
|
|
|
// 设置更新状态
|
|
// 设置更新状态
|
|
|
row.updating = true
|
|
row.updating = true
|
|
@@ -213,11 +277,10 @@ const handleUpdate = async (row: CommonBomMaterialVO) => {
|
|
|
bomNodeId: props.nodeId
|
|
bomNodeId: props.nodeId
|
|
|
}
|
|
}
|
|
|
// 调用更新接口
|
|
// 调用更新接口
|
|
|
- await CommonBomMaterialApi.updateCommonBomMaterial(updateParams)
|
|
|
|
|
|
|
+ await CommonBomMaterialApi.updateCommonBomMaterial(updateParams as CommonBomMaterialVO)
|
|
|
// 更新成功反馈
|
|
// 更新成功反馈
|
|
|
message.success('数量更新成功')
|
|
message.success('数量更新成功')
|
|
|
- // 可选:刷新父组件数据
|
|
|
|
|
- // emit('refresh')
|
|
|
|
|
|
|
+ emit('refresh')
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
ElMessage.error('更新失败')
|
|
ElMessage.error('更新失败')
|
|
|
} finally {
|
|
} finally {
|
|
@@ -226,7 +289,9 @@ const handleUpdate = async (row: CommonBomMaterialVO) => {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/** 删除BOM节点已经挂载的物料 */
|
|
/** 删除BOM节点已经挂载的物料 */
|
|
|
-const handleDelete = async (row) => {
|
|
|
|
|
|
|
+const handleDelete = async (row: MaterialDetailRow) => {
|
|
|
|
|
+ if (!props.nodeId) return
|
|
|
|
|
+
|
|
|
try {
|
|
try {
|
|
|
// 删除的二次确认
|
|
// 删除的二次确认
|
|
|
await message.delConfirm()
|
|
await message.delConfirm()
|
|
@@ -234,18 +299,19 @@ const handleDelete = async (row) => {
|
|
|
await CommonBomMaterialApi.deleteBomMaterial(props.nodeId, row.code)
|
|
await CommonBomMaterialApi.deleteBomMaterial(props.nodeId, row.code)
|
|
|
message.success(t('common.delSuccess'))
|
|
message.success(t('common.delSuccess'))
|
|
|
// 刷新列表
|
|
// 刷新列表
|
|
|
- loadMaterials(props.nodeId)
|
|
|
|
|
|
|
+ await loadMaterials(props.nodeId, false)
|
|
|
|
|
+ emit('refresh')
|
|
|
} catch {}
|
|
} catch {}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 打开抽屉
|
|
// 打开抽屉
|
|
|
const openDrawer = () => {
|
|
const openDrawer = () => {
|
|
|
- drawerVisible.value = true
|
|
|
|
|
|
|
+ emit('update:modelValue', true)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 关闭抽屉
|
|
// 关闭抽屉
|
|
|
const closeDrawer = () => {
|
|
const closeDrawer = () => {
|
|
|
- drawerVisible.value = false
|
|
|
|
|
|
|
+ handleClose()
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 关闭抽屉
|
|
// 关闭抽屉
|
|
@@ -257,97 +323,205 @@ const handleClose = () => {
|
|
|
|
|
|
|
|
defineExpose({ openDrawer, closeDrawer, loadMaterials }) // 暴露方法给父组件
|
|
defineExpose({ openDrawer, closeDrawer, loadMaterials }) // 暴露方法给父组件
|
|
|
|
|
|
|
|
|
|
+onMounted(() => {
|
|
|
|
|
+ window.addEventListener('resize', updateWindowWidth)
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+onUnmounted(() => {
|
|
|
|
|
+ window.removeEventListener('resize', updateWindowWidth)
|
|
|
|
|
+})
|
|
|
</script>
|
|
</script>
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
<style lang="scss" scoped>
|
|
|
|
|
+.drawer-header {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ gap: 16px;
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
-/* 添加表格样式优化 */
|
|
|
|
|
-.el-table {
|
|
|
|
|
- :deep(.cell) {
|
|
|
|
|
- white-space: nowrap; /* 防止单元格内容换行 */
|
|
|
|
|
- }
|
|
|
|
|
|
|
+.drawer-header__main {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ gap: 12px;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- /* 表头样式 */
|
|
|
|
|
- :deep(th.el-table__cell) {
|
|
|
|
|
- background-color: #f5f7fa;
|
|
|
|
|
- font-weight: bold;
|
|
|
|
|
- color: #606266;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+.drawer-header__icon {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ width: 44px;
|
|
|
|
|
+ height: 44px;
|
|
|
|
|
+ color: var(--el-color-primary);
|
|
|
|
|
+ background: rgb(64 158 255 / 12%);
|
|
|
|
|
+ border: 1px solid rgb(64 158 255 / 18%);
|
|
|
|
|
+ border-radius: 8px;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-/* 优化输入框样式 */
|
|
|
|
|
-.el-input {
|
|
|
|
|
- width: 80px;
|
|
|
|
|
|
|
+.drawer-title {
|
|
|
|
|
+ font-size: 18px;
|
|
|
|
|
+ font-weight: 600;
|
|
|
|
|
+ color: var(--el-text-color-primary);
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- :deep(.el-input__inner) {
|
|
|
|
|
- text-align: center;
|
|
|
|
|
- padding: 0 5px;
|
|
|
|
|
- }
|
|
|
|
|
- &.error-input :deep(.el-input__inner) {
|
|
|
|
|
- border-color: #f56c6c;
|
|
|
|
|
- background-color: #fff6f7;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+.drawer-subtitle {
|
|
|
|
|
+ margin-top: 4px;
|
|
|
|
|
+ font-size: 13px;
|
|
|
|
|
+ color: var(--el-text-color-secondary);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.drawer-body {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ gap: 18px;
|
|
|
|
|
+ height: 100%;
|
|
|
|
|
+ padding: 4px 4px 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.info-card {
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ background: var(--el-bg-color);
|
|
|
|
|
+ border: 1px solid var(--el-border-color-lighter);
|
|
|
|
|
+ border-radius: 8px;
|
|
|
|
|
+ box-shadow: 0 10px 28px rgb(31 45 61 / 6%);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-/* 错误提示样式 */
|
|
|
|
|
-:deep(.el-form-item__error) {
|
|
|
|
|
|
|
+.info-card__header {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ min-height: 58px;
|
|
|
|
|
+ padding: 0 20px;
|
|
|
|
|
+ background: linear-gradient(90deg, rgb(64 158 255 / 8%) 0%, rgb(255 255 255 / 0%) 72%);
|
|
|
|
|
+ border-bottom: 1px solid var(--el-border-color-lighter);
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.info-card__title {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ gap: 10px;
|
|
|
|
|
+ font-size: 16px;
|
|
|
|
|
+ font-weight: 600;
|
|
|
|
|
+ line-height: 22px;
|
|
|
|
|
+ color: var(--el-text-color-primary);
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.info-card__marker {
|
|
|
|
|
+ width: 4px;
|
|
|
|
|
+ height: 18px;
|
|
|
|
|
+ background: var(--el-color-primary);
|
|
|
|
|
+ border-radius: 2px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.info-card__body {
|
|
|
|
|
+ padding: 20px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.detail-grid {
|
|
|
|
|
+ display: grid;
|
|
|
|
|
+ grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
|
|
|
+ gap: 16px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.detail-item {
|
|
|
|
|
+ min-width: 0;
|
|
|
|
|
+ padding: 14px 16px;
|
|
|
|
|
+ background: var(--el-fill-color-lighter);
|
|
|
|
|
+ border: 1px solid var(--el-border-color-lighter);
|
|
|
|
|
+ border-radius: 8px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.detail-item__label {
|
|
|
|
|
+ margin-bottom: 6px;
|
|
|
|
|
+ font-size: 13px;
|
|
|
|
|
+ line-height: 18px;
|
|
|
|
|
+ color: var(--el-text-color-secondary);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.detail-item__value {
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ font-size: 15px;
|
|
|
|
|
+ font-weight: 600;
|
|
|
|
|
+ line-height: 22px;
|
|
|
|
|
+ color: var(--el-text-color-primary);
|
|
|
|
|
+ text-overflow: ellipsis;
|
|
|
|
|
+ white-space: nowrap;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.material-card {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ min-height: 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.material-card__body {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ gap: 12px;
|
|
|
|
|
+ height: 100%;
|
|
|
|
|
+ min-height: 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.material-total {
|
|
|
|
|
+ font-size: 13px;
|
|
|
|
|
+ color: var(--el-text-color-secondary);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.material-table {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ min-height: 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.quantity-form {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.quantity-form :deep(.el-form-item) {
|
|
|
|
|
+ width: 96px;
|
|
|
|
|
+ margin-bottom: 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.quantity-form :deep(.el-form-item__error) {
|
|
|
position: absolute;
|
|
position: absolute;
|
|
|
top: 100%;
|
|
top: 100%;
|
|
|
left: 0;
|
|
left: 0;
|
|
|
padding-top: 2px;
|
|
padding-top: 2px;
|
|
|
font-size: 12px;
|
|
font-size: 12px;
|
|
|
line-height: 1;
|
|
line-height: 1;
|
|
|
- color: #f56c6c;
|
|
|
|
|
|
|
+ color: var(--el-color-danger);
|
|
|
white-space: nowrap;
|
|
white-space: nowrap;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-/* 更新按钮自定义样式 */
|
|
|
|
|
-.el-button--success {
|
|
|
|
|
- background-color: #e8f5e9;
|
|
|
|
|
- border-color: #c8e6c9;
|
|
|
|
|
- color: #2e7d32;
|
|
|
|
|
-
|
|
|
|
|
- &:hover {
|
|
|
|
|
- background-color: #c8e6c9;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+.quantity-input :deep(.el-input__inner) {
|
|
|
|
|
+ text-align: center;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-.info-header {
|
|
|
|
|
|
|
+.table-actions {
|
|
|
display: flex;
|
|
display: flex;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ gap: 8px;
|
|
|
align-items: center;
|
|
align-items: center;
|
|
|
- padding: 18px 24px;
|
|
|
|
|
- background-color: #f5f7fa;
|
|
|
|
|
- border-bottom: 1px solid #ebeef5;
|
|
|
|
|
- margin-bottom: 20px;
|
|
|
|
|
-
|
|
|
|
|
- .info-item {
|
|
|
|
|
- flex: 1; /* 平分宽度 */
|
|
|
|
|
- display: flex;
|
|
|
|
|
- align-items: center; /* 垂直居中 */
|
|
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+@media (width <= 768px) {
|
|
|
|
|
+ .drawer-body {
|
|
|
|
|
+ padding: 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- .separator {
|
|
|
|
|
- width: 1px;
|
|
|
|
|
- height: 40px;
|
|
|
|
|
- background-color: #dcdfe6;
|
|
|
|
|
- margin: 0 24px;
|
|
|
|
|
|
|
+ .info-card__header {
|
|
|
|
|
+ padding: 12px 16px;
|
|
|
|
|
+ align-items: flex-start;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ gap: 4px;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- .info-label {
|
|
|
|
|
- font-weight: bold;
|
|
|
|
|
- color: #606266;
|
|
|
|
|
- margin-right: 8px; /* 标签和值之间的间距 */
|
|
|
|
|
- font-size: 14px;
|
|
|
|
|
- white-space: nowrap; /* 防止标签换行 */
|
|
|
|
|
|
|
+ .info-card__body {
|
|
|
|
|
+ padding: 16px;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- .info-value {
|
|
|
|
|
- color: #303133;
|
|
|
|
|
- font-size: 16px;
|
|
|
|
|
- font-weight: 500;
|
|
|
|
|
- white-space: nowrap; /* 防止值换行 */
|
|
|
|
|
- overflow: hidden;
|
|
|
|
|
- text-overflow: ellipsis; /* 超出部分显示省略号 */
|
|
|
|
|
|
|
+ .detail-grid {
|
|
|
|
|
+ grid-template-columns: minmax(0, 1fr);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
</style>
|
|
</style>
|