You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3013 lines
92 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<div>
<!-- 盘点计划 Section -->
<div class="content-wrapper">
<div class="page-header">
<h1 class="page-title">盘点计划</h1>
<Button type="primary" @click="showPlanModal('new')"></Button>
</div>
<!-- Plan Search Filters -->
<div class="search-filters">
<div class="filter-item">
<span class="selector-item__label">关键词:</span>
<Input
v-model="planSearch.keyword"
style="width: 180px"
:clearable="true"
placeholder="计划名称/编号"
/>
</div>
<div class="filter-item">
<span class="selector-item__label">计划日期:</span>
<DatePicker
v-model="planSearch.dateRange"
type="daterange"
split-panels
style="width: 200px"
:clearable="true"
/>
</div>
<div class="filter-item">
<Button type="primary" @click="searchPlans">查询</Button>
<Button style="margin-left: 10px" @click="resetPlanSearch">重置</Button>
</div>
</div>
<!-- Plan Table -->
<Table :columns="planColumns" :data="planList" :loading="planLoading" height="400">
<template slot="status" slot-scope="{ row }">
<Tag :color="getStatusColor(row.status)">{{ getStatusText(row.status) }}</Tag>
</template>
<template slot="progress" slot-scope="{ row }">
<Progress :percent="getPlanProgress(row)" :stroke-width="15" />
</template>
<template slot="action" slot-scope="{ row }">
<div style="display: flex; gap: 8px; justify-content: center">
<Button
type="primary"
size="small"
style="border-radius: 6px"
@click="showInventorySelectModal(row.id)"
>选择对象</Button
>
<!-- <Button
v-if="row.status === 2"
type="success"
size="small"
style="border-radius: 6px"
ghost
@click="showSummaryModal(row)"
>盘点小结</Button
> -->
<template v-if="row.status === 2">
<el-dropdown trigger="hover" @command="command => handleMoreCommand(command, row)">
<Button type="info" size="small" style="border-radius: 6px" ghost
>更多<i class="el-icon-arrow-down el-icon--right"
/></Button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="edit">编辑</el-dropdown-item>
<el-dropdown-item command="delete">删除</el-dropdown-item>
<el-dropdown-item command="view">查看</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
<template v-else>
<Button
type="primary"
size="small"
style="border-radius: 6px"
ghost
@click="showPlanModal('edit', row)"
>编辑</Button
>
<Button
type="error"
size="small"
style="border-radius: 6px"
ghost
@click="deletePlan(row.id)"
>删除</Button
>
<Button
type="info"
size="small"
style="border-radius: 6px"
ghost
@click="viewPlanDetail(row)"
>查看</Button
>
</template>
</div>
</template>
</Table>
<!-- Plan Pagination -->
<div class="pagination-container">
<el-pagination
:current-page="planSearch.pageIndex"
:page-sizes="[10, 20, 50, 100]"
:page-size="planSearch.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="planTotal"
@size-change="handlePlanPageSizeChange"
@current-change="handlePlanPageChange"
/>
</div>
</div>
<!-- 历史盘点计划 Section -->
<div class="content-wrapper" style="margin-top: 20px">
<div class="page-header">
<h1 class="page-title">历史盘点计划</h1>
</div>
<Tabs v-model="historyTab" @on-click="handleHistoryTabChange">
<!-- 计划内 Tab -->
<TabPane label="计划内" name="plan">
<!-- Plan Search Filters -->
<div class="search-filters">
<div class="filter-item">
<span class="selector-item__label">关键词:</span>
<Input
v-model="historyPlanSearch.keyword"
style="width: 180px"
:clearable="true"
placeholder="计划名称/编号"
/>
</div>
<div class="filter-item">
<span class="selector-item__label">计划日期:</span>
<DatePicker
v-model="historyPlanSearch.dateRange"
type="daterange"
split-panels
style="width: 200px"
:clearable="true"
/>
</div>
<div class="filter-item">
<Button type="primary" @click="searchHistoryPlans">查询</Button>
<Button style="margin-left: 10px" @click="resetHistoryPlanSearch">重置</Button>
</div>
</div>
<!-- Plan Table -->
<Table :columns="planColumns" :data="historyPlanList" :loading="historyPlanLoading">
<template slot="status" slot-scope="{ row }">
<Tag :color="getStatusColor(row.status)">{{ getStatusText(row.status) }}</Tag>
</template>
<template slot="progress" slot-scope="{ row }">
<Progress :percent="getPlanProgress(row)" :stroke-width="15" />
</template>
<template slot="action" slot-scope="{ row }">
<div style="display: flex; gap: 8px; justify-content: center">
<Button
type="success"
size="small"
style="border-radius: 6px"
ghost
@click="showSummaryModal(row)"
>盘点小结</Button
>
<el-dropdown trigger="hover" @command="command => handleMoreCommand(command, row)">
<Button type="info" size="small" style="border-radius: 6px" ghost
>更多<i class="el-icon-arrow-down el-icon--right"
/></Button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="edit">编辑</el-dropdown-item>
<el-dropdown-item command="delete">删除</el-dropdown-item>
<el-dropdown-item command="view">查看</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</template>
</Table>
<!-- Plan Pagination -->
<div class="pagination-container">
<el-pagination
:current-page="historyPlanSearch.pageIndex"
:page-sizes="[10, 20, 50, 100]"
:page-size="historyPlanSearch.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="historyPlanTotal"
@size-change="handleHistoryPlanPageSizeChange"
@current-change="handleHistoryPlanPageChange"
/>
</div>
</TabPane>
<!-- 计划外 Tab -->
<TabPane label="计划外" name="outside">
<!-- List Search Filters -->
<div class="search-filters">
<div class="filter-item">
<span class="selector-item__label">盘点日期:</span>
<DatePicker
v-model="listSearch.dateRange"
type="daterange"
split-panels
style="width: 200px"
:clearable="true"
/>
</div>
<div class="filter-item">
<Button type="primary" @click="searchList">查询</Button>
<Button style="margin-left: 10px" @click="resetListSearch">重置</Button>
</div>
</div>
<!-- History List Table -->
<Table :columns="outsideListColumns" :data="inventoryList" :loading="listLoading" border height="400">
<template slot="status" slot-scope="{ row }">
<Tag :color="getInventoryStatusColor(row.status)">{{
getInventoryStatusText(row.status)
}}</Tag>
</template>
<template slot="responsible_admin" slot-scope="{ row }">
{{ row.responsible_admin ? row.responsible_admin.name : '-' }}
</template>
<template slot="photos" slot-scope="{ row }">
<div v-if="row.files && row.files.length" class="photo-list">
<div v-for="(file, index) in row.files.slice(0, 3)" :key="index" class="photo-item">
<img :src="file.url" @click="previewImage(file.url)" />
</div>
<div v-if="row.files.length > 3" class="photo-more">
+{{ row.files.length - 3 }}
</div>
</div>
<span v-else>-</span>
</template>
</Table>
<!-- List Pagination -->
<div class="pagination-container">
<el-pagination
:current-page="listSearch.pageIndex"
:page-sizes="[10, 20, 50, 100]"
:page-size="listSearch.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="listTotal"
@size-change="handleListPageSizeChange"
@current-change="handleListPageChange"
/>
</div>
</TabPane>
</Tabs>
</div>
<!-- Plan Create/Edit Modal -->
<Modal v-model="planModal.visible" :title="planModal.title">
<Form ref="planForm" :model="planModal.form" :rules="planModal.rules" width="80">
<FormItem label="计划名称" prop="name">
<Input v-model="planModal.form.name" placeholder="请输入计划名称" :clearable="true" />
</FormItem>
<FormItem label="计划日期" prop="dateRange">
<DatePicker
v-model="planModal.form.dateRange"
type="daterange"
split-panels
style="width: 100%"
:clearable="true"
:editable="false"
@on-clear="handleDateClear"
/>
</FormItem>
<FormItem label="盘点类型" prop="type">
<Select v-model="planModal.form.type" style="width: 200px">
<Option :value="1">年度</Option>
<Option :value="2"></Option>
</Select>
</FormItem>
<FormItem label="备注" prop="remark">
<Input
v-model="planModal.form.remark"
type="textarea"
:rows="3"
placeholder="请输入备注信息"
/>
</FormItem>
</Form>
<template slot="footer">
<Button @click="planModal.visible = false">取消</Button>
<Button type="primary" @click="handlePlanSubmit">确定</Button>
</template>
</Modal>
<!-- Inventory Selection Modal -->
<Modal
v-model="materialModal.visible"
title="选择盘点物资"
width="70%"
@on-cancel="handleMaterialModalClose"
>
<div style="display: flex; justify-content: flex-start; flex-wrap: wrap">
<div class="selector-item">
<el-input
v-model="materialModal.keyword"
style="width: 120px; margin-right: 10px"
placeholder="物资名称搜索"
/>
</div>
<div class="selector-item">
<el-cascader
v-model="materialModal.fenlei"
placeholder="请选择所属种类"
ref="cascaders"
clearable
popper-class="select_popper"
style="margin-right: 10px; flex-basis: 20%"
:options="fenleiList"
:props="{ label: 'name', value: 'id' }"
@change="
e => {
changeFenlei(e)
}
"
/>
</div>
<div class="selector-item">
<el-select
clearable
v-model="materialModal.suozaicangku"
style="width: 100%"
placeholder="请选择所在仓库"
>
<el-option
v-for="item in cangkuList"
:key="item.id"
:label="item.cangkumingcheng"
:value="item.id"
/>
</el-select>
</div>
<div class="selector-item">
<el-date-picker
type="daterange"
range-separator="至"
start-placeholder="入库日期开始"
end-placeholder="入库日期结束"
format="yyyy-MM-dd"
value-format="yyyy-MM-dd"
v-model="materialModal.rukuriqi"
></el-date-picker>
</div>
<div class="selector-item">
<el-date-picker
format="yyyy-MM-dd"
type="daterange"
range-separator="至"
start-placeholder="生产日期开始"
end-placeholder="生产日期结束"
value-format="yyyy-MM-dd"
v-model="materialModal.shengchanriqi"
></el-date-picker>
</div>
<div class="selector-item">
<el-select
clearable
v-model="materialModal.wuzizhuangtai"
style="width: 100%"
placeholder="请选择物资状态"
>
<el-option
v-for="item in paraOptions.materials_status"
:key="item.id"
:label="item.value"
:value="item.id"
/>
</el-select>
</div>
<div class="selector-item">
<el-select
clearable
v-model="materialModal.chanquanxinxi"
style="width: 100%"
placeholder="请选择产权信息"
>
<el-option
v-for="item in paraOptions.materials_property"
:key="item.id"
:label="item.value"
:value="item.id"
/>
</el-select>
</div>
<div class="selector-item">
<el-select
clearable
v-model="materialModal.chubeifangshi"
style="width: 100%"
placeholder="请选择储备方式"
>
<el-option
v-for="item in paraOptions.material_reserve"
:key="item.id"
:label="item.value"
:value="item.id"
/>
</el-select>
</div>
<div class="selector-item">
<el-select
clearable
v-model="materialModal.dengjifenlei"
style="width: 100%"
placeholder="请选择等级分类"
>
<el-option
v-for="item in paraOptions.dengjifenlei"
:key="item.id"
:label="item.value"
:value="item.id"
/>
</el-select>
</div>
<div>
<el-button type="primary" style="margin-left: 10px" @click="searchMaterials"
>查询</el-button
>
<el-button type="primary" style="margin-left: 10px" @click="resetMaterialSearch"
>重置</el-button
>
</div>
</div>
<xy-table
ref="materialTable"
:key="materialModal.tableKey"
v-loading="materialModal.loading"
:pageSize="materialModal.pageSize"
:pageIndex="materialModal.pageIndex"
:span-method="objectSpanMethod"
:list="materialList"
:total="materialModal.total"
:table-item="materialTable"
:auths="[]"
:default-selections="getSelectedRows()"
@selection-change="selectionChange"
@pageSizeChange="handleMaterialPageSizeChange"
@pageIndexChange="handleMaterialPageChange"
>
<template v-slot:btns>
<el-table-column
fixed="right"
align="center"
label="操作"
width="120"
header-align="center"
>
<template slot-scope="scope">
<div style="display: flex; gap: 8px; justify-content: center">
<el-button
:type="isSelected(scope.row) ? 'warning' : 'success'"
size="small"
style="border-radius: 6px"
@click="toggleMaterialSelection(scope.row, scope.$index)"
>
{{ isSelected(scope.row) ? '移出计划' : '加入计划' }}
</el-button>
</div>
</template>
</el-table-column>
</template>
</xy-table>
<template slot="footer">
<Button @click="handleMaterialModalClose">取消</Button>
<Button type="primary" @click="handleMaterialSubmit">确定</Button>
</template>
</Modal>
<!-- 盘点任务详情弹窗 -->
<Modal v-model="detailModal.visible" title="盘点任务详情" width="1000" :mask-closable="true">
<div v-if="detailModal.data" class="detail-content">
<div class="detail-header">
<div class="detail-item">
<span class="label">盘点单号:</span>
<span class="value">{{ detailModal.data.no }}</span>
</div>
<div class="detail-item">
<span class="label">所属计划:</span>
<span class="value">{{ detailModal.data.planName }}</span>
</div>
<div class="detail-item">
<span class="label">盘点区域:</span>
<span class="value">{{ detailModal.data.area }}</span>
</div>
<div class="detail-item">
<span class="label">执行人:</span>
<span class="value">{{ detailModal.data.executor }}</span>
</div>
<div class="detail-item">
<span class="label">开始时间:</span>
<span class="value">{{ detailModal.data.startTime }}</span>
</div>
<div class="detail-item">
<span class="label">完成时间:</span>
<span class="value">{{ detailModal.data.endTime || '-' }}</span>
</div>
<div class="detail-item">
<span class="label">状态:</span>
<span class="value">
<Tag :color="getInventoryStatusColor(detailModal.data.status)">
{{ getInventoryStatusText(detailModal.data.status) }}
</Tag>
</span>
</div>
</div>
<div class="material-info-section">
<h3>物资基本信息</h3>
<div class="material-info-content">
<div class="info-item">
<span class="label">物资名称:</span>
<span class="value">{{
(detailModal.data.material_info &&
detailModal.data.material_info.zichanmingcheng) ||
'-'
}}</span>
</div>
<!-- <div class="info-item">
<span class="label">物资代码:</span>
<span class="value">{{ detailModal.data.material_info && detailModal.data.material_info.wuzibianma || '-' }}</span>
</div> -->
<div class="info-item">
<span class="label">物资型号:</span>
<span class="value">{{
(detailModal.data.material_info && detailModal.data.material_info.guigexinghao) ||
'-'
}}</span>
</div>
<div class="info-item">
<span class="label">计量单位:</span>
<span class="value">{{
(detailModal.data.material_info && detailModal.data.material_info.jiliangdanwei) ||
'-'
}}</span>
</div>
<div class="info-item">
<span class="label">当前库存:</span>
<span class="value">{{
(detailModal.data.material_info &&
detailModal.data.material_info.inventorys_total) ||
'0'
}}</span>
</div>
</div>
</div>
<div class="history-section">
<h3>盘点历史记录</h3>
<Table
:columns="detailColumns"
:data="detailModal.data.history || []"
:loading="detailModal.loading"
border
>
<template slot="status" slot-scope="{ row }">
<Tag :color="getInventoryStatusColor(row.status)">{{
getInventoryStatusText(row.status)
}}</Tag>
</template>
<template slot="photos" slot-scope="{ row }">
<div v-if="row.files && row.files.length" class="photo-list">
<div v-for="(file, index) in row.files.slice(0, 3)" :key="index" class="photo-item">
<img :src="file.url" @click="previewImage(file.url)" />
</div>
<div v-if="row.files.length > 3" class="photo-more">
+{{ row.files.length - 3 }}
</div>
</div>
<span v-else>-</span>
</template>
</Table>
<div class="pagination-container">
<el-pagination
:current-page="detailModal.pageIndex"
:page-sizes="[10, 20, 50, 100]"
:page-size="detailModal.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="detailModal.total"
@size-change="handleDetailPageSizeChange"
@current-change="handleDetailPageChange"
/>
</div>
</div>
</div>
<template slot="footer">
<Button @click="detailModal.visible = false">关闭</Button>
</template>
</Modal>
<!-- 预览弹窗 -->
<div v-if="previewUrl" class="image-preview-modal" @click="closePreview">
<img :src="previewUrl" class="image-preview-large" />
</div>
<!-- Plan Detail Modal -->
<Modal
v-model="planDetailModal.visible"
title="盘点计划详情"
width="1000"
:mask-closable="true"
>
<div v-if="planDetailModal.data" class="plan-detail-content">
<div class="detail-header">
<div class="detail-item">
<span class="label">计划编号:</span>
<span class="value">{{ planDetailModal.data.no }}</span>
</div>
<div class="detail-item">
<span class="label">计划名称:</span>
<span class="value">{{ planDetailModal.data.name }}</span>
</div>
<div class="detail-item">
<span class="label">开始日期:</span>
<span class="value">{{ planDetailModal.data.start_date }}</span>
</div>
<div class="detail-item">
<span class="label">结束日期:</span>
<span class="value">{{ planDetailModal.data.end_date }}</span>
</div>
<div class="detail-item">
<span class="label">状态:</span>
<span class="value">
<Tag :color="getStatusColor(planDetailModal.data.status)">
{{ getStatusText(planDetailModal.data.status) }}
</Tag>
</span>
</div>
<div class="detail-item">
<span class="label">备注:</span>
<span class="value">{{ planDetailModal.data.remark || '-' }}</span>
</div>
</div>
<div class="inventory-list-section">
<h3>盘点物资列表</h3>
<Table
:columns="planDetailColumns"
:data="planDetailModal.inventoryList"
:loading="planDetailModal.loading"
border
>
<template slot="status" slot-scope="{ row }">
<Tag :color="getInventoryStatusColor(row.status)">{{
getInventoryStatusText(row.status)
}}</Tag>
</template>
<template slot="photos" slot-scope="{ row }">
<div v-if="row.files && row.files.length" class="photo-list">
<div v-for="(file, index) in row.files.slice(0, 3)" :key="index" class="photo-item">
<img :src="file.url" @click="previewImage(file.url)" />
</div>
<div v-if="row.files.length > 3" class="photo-more">
+{{ row.files.length - 3 }}
</div>
</div>
<span v-else>-</span>
</template>
</Table>
<div class="pagination-container">
<el-pagination
:current-page="planDetailModal.pageIndex"
:page-sizes="[10, 20, 50, 100]"
:page-size="planDetailModal.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="planDetailModal.total"
@size-change="handlePlanDetailPageSizeChange"
@current-change="handlePlanDetailPageChange"
/>
</div>
</div>
</div>
<template slot="footer">
<Button @click="planDetailModal.visible = false">关闭</Button>
</template>
</Modal>
<!-- 盘点小结 Modal -->
<Modal v-model="summaryModal.visible" title="盘点小结" width="800">
<div>
<div id="print-table">
<div style="text-align: center; font-size: 20px; font-weight: bold; margin-bottom: 12px">
盘点小结
</div>
<table class="summary-table">
<tr>
<td>盘点计划名称</td>
<td>{{ summaryModal.data ? summaryModal.data.name : '' }}</td>
</tr>
<tr>
<td>计划开始日期</td>
<td>{{ summaryModal.data ? summaryModal.data.planStart : '' }}</td>
</tr>
<tr>
<td>计划结束日期</td>
<td>{{ summaryModal.data ? summaryModal.data.planEnd : '' }}</td>
</tr>
<tr>
<td>实际开始日期</td>
<td>{{ summaryModal.data ? summaryModal.data.actualStart : '' }}</td>
</tr>
<tr>
<td>实际结束日期</td>
<td>{{ summaryModal.data ? summaryModal.data.actualEnd : '' }}</td>
</tr>
<tr>
<td>计划盘点清单数量</td>
<td>{{ summaryModal.data ? summaryModal.data.planCount : '' }}</td>
</tr>
<tr>
<td>实际盘点清单数量</td>
<td>{{ summaryModal.data ? summaryModal.data.actualCount : '' }}</td>
</tr>
<tr>
<td class="sign-cell">签字区</td>
<td style="text-align: center">
<img :src="summaryModal.signImage" alt="" style="max-width: 200px; max-height: 100px; border: 1px solid #eee; cursor: pointer">
</td>
</tr>
</table>
</div>
<div style="margin: 24px 0 8px 0">
<span style="font-weight: bold">签字图片上传:</span>
<div v-if="summaryModal.signImage" style="margin-top: 8px">
<div style="position: relative; display: inline-block">
<img
:src="summaryModal.signImage"
style="max-width: 200px; max-height: 100px; border: 1px solid #eee; cursor: pointer"
@click="previewImage(summaryModal.signImage)"
/>
<Button
type="error"
size="small"
style="position: absolute; top: 5px; right: 5px"
@click.stop="
summaryModal.signImage = null
summaryModal.signImageId = null
"
>
重新上传
</Button>
</div>
</div>
<div v-else style="margin-top: 8px">
<Upload
:before-upload="beforeSignUpload"
:on-success="handleSignUpload"
:show-upload-list="false"
:action="baseUrl + 'api/admin/upload-file'"
>
<Button type="primary" size="small">上传签字图片</Button>
</Upload>
</div>
</div>
</div>
<template slot="footer">
<Button v-print="'#print-table'">打印</Button>
<Button type="primary" style="margin-left: 8px" @click="handleSummarySubmit">提交</Button>
</template>
</Modal>
</div>
</template>
<script>
import {
saveStocktakingPlan,
getStocktakingPlanList,
deleteStocktakingPlan,
getStocktakingPlanLinkList,
getStocktakingHistoryList,
deleteStocktakingPlanLink
} from '@/api/system/stocktaking'
import { index } from '@/api/inventory.js'
import { index as getFenleilist } from '@/api/fenlei.js'
import { index as baseFormIndex } from '@/api/system/baseForm.js'
import { getparameteritemMore } from '@/api/system/dictionary.js'
import qs from 'qs'
import request from '@/utils/request'
export default {
data() {
return {
baseUrl: process.env.VUE_APP_BASE_API || window.location.origin + '/',
planSearch: {
keyword: '',
dateRange: [],
pageIndex: 1,
pageSize: 10
},
planList: [],
planTotal: 0,
planLoading: false,
planColumns: [
{ title: '计划编号', key: 'no' },
{ title: '计划名称', key: 'name' },
{ title: '对象数量', key: 'chart_total' },
{
title: '盘点类型',
key: 'type',
render: (h, params) => {
const typeMap = {
1: '年度',
2: '季度'
}
return h('span', typeMap[params.row.type] || '-')
}
},
{ title: '开始日期', key: 'start_date' },
{ title: '结束日期', key: 'end_date' },
{
title: '状态',
slot: 'status',
key: 'status'
},
{
title: '进度',
slot: 'progress',
width: 200
},
{
title: '操作',
slot: 'action',
width: 280
}
],
listSearch: {
keyword: '',
status: '',
dateRange: [],
pageIndex: 1,
pageSize: 10
},
inventoryList: [],
listTotal: 0,
listLoading: false,
historyTab: 'plan',
historyPlanSearch: {
keyword: '',
dateRange: [],
pageIndex: 1,
pageSize: 10
},
historyPlanList: [],
historyPlanTotal: 0,
historyPlanLoading: false,
listColumns: [
{ title: '盘点单号', key: 'no' },
{
title: '所属计划',
slot: 'planName',
key: 'material_infos_plan.name'
},
{
title: '盘点区域',
slot: 'area',
key: 'material_info.suozaicangku'
},
{
title: '执行人',
slot: 'executor',
key: 'responsible_admin.name'
},
{
title: '开始时间',
slot: 'startTime',
key: 'material_infos_plan.start_date'
},
{
title: '完成时间',
slot: 'endTime',
key: 'material_infos_plan.end_date'
},
{
title: '状态',
slot: 'status',
key: 'status'
},
{
title: '操作',
slot: 'action',
width: 100
}
],
planModal: {
visible: false,
title: '新建盘点计划',
form: {
id: '',
name: '',
dateRange: [],
type: 1, // 默认为日常检查
remark: ''
},
rules: {
name: [{ required: true, message: '请输入计划名称', trigger: 'blur' }],
dateRange: [
{
required: true,
type: 'array',
min: 2,
message: '请选择计划日期',
trigger: 'change',
validator: (rule, value, callback) => {
if (!value || value.length !== 2) {
callback(new Error('请选择计划日期'))
} else {
callback()
}
}
}
]
}
},
materialModal: {
visible: false,
loading: false,
keyword: '',
fenlei: '',
wuzizhuangtai: '',
chanquanxinxi: '',
chubeifangshi: '',
suozaicangku: '',
rukuriqi: '',
shengchanriqi: '',
dengjifenlei: '',
currentPlanId: '',
pageIndex: 1,
pageSize: 40,
total: 0,
selectedMaterialIds: new Set(),
selectedMaterialData: new Map(), // 存储选中物资的详细数据 {inventorys_id: {id, inventorys_id}}
isInitialLoad: true,
isUpdatingSelection: false, // 标志是否正在程序更新选中状态
tableKey: 0 // 用于强制重新渲染表格
},
materialList: [],
fenleiList: [],
cangkuList: [],
paraOptions: {
materials_status: [],
material_reserve: [],
materials_property: [],
dengjifenlei: []
},
materialTable: [
{
type: 'selection',
fixed: 'left',
selectable: (row, index) => {
// 根据选中状态返回是否可选
return true
},
reserveSelection: true // 保留选中状态
},
{
label: '物资信息',
align: 'left',
prop: 'wuzibianma_material_infos_wuzibianma_relation',
multiHd: [
{
label: '一级分类',
width: 120,
prop: 'wuzibianma_material_infos_wuzibianma_relation.material_info_type',
align: 'center',
formatter: (cell, data, value) => {
return value ? value.split('-')[0] : ''
}
},
{
label: '二级分类',
width: 120,
prop: 'wuzibianma_material_infos_wuzibianma_relation.material_info_type',
align: 'center',
formatter: (cell, data, value) => {
return value
? value.split('-').length > 1
? value.split('-')[1]
: value.split('-')[0]
: ''
}
},
{
label: '所属种类',
width: 120,
prop: 'wuzibianma_material_infos_wuzibianma_relation.fenlei_detail.name',
align: 'center'
},
{
label: '物资名称',
prop: 'zichanmingcheng',
align: 'center',
width: 180,
fixed: 'left'
},
{
label: '物资类型',
width: 120,
prop: 'wuzileixing',
align: 'center'
},
{
label: '物资型号',
prop: 'wuzibianma_material_infos_wuzibianma_relation.guigexinghao',
align: 'center',
width: 180
},
{
label: '物资规格',
prop: 'wuzibianma_material_infos_wuzibianma_relation.wuziguige',
align: 'center',
width: 180
},
{
label: '单位',
width: 120,
prop: 'wuzibianma_material_infos_wuzibianma_relation.jiliangdanwei',
align: 'center'
}
]
},
{
label: '库存信息',
prop: 'kucun',
align: 'left',
multiHd: [
{
label: '入库批次',
width: 120,
prop: 'rukupici'
},
{
label: '在库数量',
width: 120,
prop: 'zaikushuliang',
customFn: row => {
return (
<span>
{row.row.zaikushuliang}
{row.row.jiliangdanwei ? row.row.jiliangdanwei : ''}
</span>
)
}
},
{
label: '顺序号',
width: 180,
prop: 'shunxuhao',
customFn: row => {
return <span>{row.row.shunxuhao ? row.row.shunxuhao : ''}</span>
}
},
{
label: '待出库',
width: 120,
prop: 'wait_num'
}
]
},
{
label: '物资明细',
prop: 'stocks_items_info',
align: 'left',
multiHd: [
{
label: '生产日期',
width: 120,
prop: 'shengchanriqi'
},
{
label: '入库日期',
width: 120,
prop: 'rukuriqi'
},
{
label: '物资状态',
width: 120,
prop: 'wuzizhuangtai_detail.value'
},
{
label: '储备方式',
width: 120,
prop: 'chubeifangshi_detail.value'
},
{
label: '所在仓库',
width: 120,
prop: 'materialstorages.cangkumingcheng'
},
{
label: '所在货架',
width: 120,
prop: 'shelfs.huojiamingcheng'
},
{
label: '所在货架层',
width: 120,
prop: 'huojiaceng'
},
{
label: '等级分类',
width: 120,
prop: 'dengjifenlei_detail.value'
},
{
label: '产权信息',
width: 120,
prop: 'chanquanxinxi_detail.value'
},
{
label: '是否为固定资产',
width: 120,
prop: 'shifouweigudingzichan'
},
{
label: '固定资产编码',
width: 120,
prop: 'gudingzichanbianma'
},
{
label: '储备年限',
width: 120,
prop: 'chubeinianxian'
},
{
label: '存放要求',
width: 120,
prop: 'cunfangyaoqiu'
},
{
label: '维护要求',
width: 120,
prop: 'weihuyaoqiu'
},
{
label: '保养频次',
width: 120,
prop: 'equipment_maintain_config.name'
}
]
}
],
spanArr: [], // 存储合并规则的数组
position: 0, // 记录当前合并的起始位置
// 定义需要合并的列索引范围从selection列开始计数
mergeColumnRange: {
start: 1, // 基础信息分组的起始列索引
end: 8 // 基础信息分组的结束列索引
},
planMaterials: {
P202504001: ['M002', 'M004'],
P202505001: ['M001', 'M003', 'M006']
},
selectedRows: [],
detailModal: {
visible: false,
loading: false,
data: null,
pageIndex: 1,
pageSize: 10,
total: 0
},
detailColumns: [
{
title: '盘点日期',
key: 'check_date',
width: 180,
align: 'center'
},
{
title: '盘点数量',
key: 'check_num',
width: 100,
align: 'center'
},
{
title: '状态',
slot: 'status',
key: 'status',
width: 100,
align: 'center'
},
{
title: '备注',
key: 'remark',
minWidth: 200,
tooltip: true,
align: 'center'
},
{
title: '照片',
slot: 'photos',
width: 200,
align: 'center'
}
],
outsideListColumns: [
{
title: '一级分类',
key: 'yijifenlei',
width: 120,
align: 'center',
render: (h, params) => {
if (!params.row.inventory || !params.row.inventory.wuzibianma_material_infos_wuzibianma_relation) {
return h('span', '-')
}
const materialInfoType = params.row.inventory.wuzibianma_material_infos_wuzibianma_relation.material_info_type
const value = materialInfoType ? materialInfoType.split('-')[0] : ''
return h('span', value || '-')
}
},
{
title: '二级分类',
key: 'erjifenlei',
width: 120,
align: 'center',
render: (h, params) => {
if (!params.row.inventory || !params.row.inventory.wuzibianma_material_infos_wuzibianma_relation) {
return h('span', '-')
}
const materialInfoType = params.row.inventory.wuzibianma_material_infos_wuzibianma_relation.material_info_type
let value = ''
if (materialInfoType) {
const parts = materialInfoType.split('-')
value = parts.length > 1 ? parts[1] : parts[0]
}
return h('span', value || '-')
}
},
{
title: '所属种类',
key: 'suoshuzhonglei',
width: 120,
align: 'center',
render: (h, params) => {
if (!params.row.inventory || !params.row.inventory.wuzibianma_material_infos_wuzibianma_relation) {
return h('span', '-')
}
const fenleiDetail = params.row.inventory.wuzibianma_material_infos_wuzibianma_relation.fenlei_detail
const value = fenleiDetail ? fenleiDetail.name : ''
return h('span', value || '-')
}
},
{
title: '物资名称',
key: 'zichanmingcheng',
minWidth: 150,
align: 'center',
render: (h, params) => {
return h('span', params.row.inventory ? params.row.inventory.zichanmingcheng : '-')
}
},
{
title: '物资型号',
key: 'guigexinghao',
width: 120,
align: 'center',
render: (h, params) => {
return h('span', params.row.inventory ? params.row.inventory.guigexinghao : '-')
}
},
{
title: '物资规格',
key: 'wuziguige',
width: 120,
align: 'center',
render: (h, params) => {
return h('span', params.row.inventory ? params.row.inventory.wuziguige : '-')
}
},
{
title: '单位',
key: 'jiliangdanwei',
width: 80,
align: 'center',
render: (h, params) => {
return h('span', params.row.inventory ? params.row.inventory.jiliangdanwei : '-')
}
},
{
title: '原库存数量',
key: 'chushishuliang',
width: 120,
align: 'center',
render: (h, params) => {
return h('span', params.row.inventory ? params.row.inventory.chushishuliang : '-')
}
},
{
title: '盘点日期',
key: 'check_date',
width: 180,
align: 'center'
},
{
title: '盘点数量',
key: 'check_num',
width: 100,
align: 'center'
},
{
title: '状态',
slot: 'status',
key: 'status',
width: 100,
align: 'center'
},
{
title: '盘点人',
slot: 'responsible_admin',
key: 'responsible_admin',
width: 120,
align: 'center'
},
{
title: '照片',
slot: 'photos',
width: 200,
align: 'center'
},
{
title: '备注',
key: 'remark',
minWidth: 200,
tooltip: true,
align: 'center'
}
],
previewUrl: '',
planDetailModal: {
visible: false,
loading: false,
data: null,
pageIndex: 1,
pageSize: 10,
total: 0,
inventoryList: []
},
planDetailColumns: [
{
title: '一级分类',
key: 'yijifenlei',
width: 120,
render: (h, params) => {
if (!params.row.inventory || !params.row.inventory.wuzibianma_material_infos_wuzibianma_relation) {
return h('span', '-')
}
const materialInfoType = params.row.inventory.wuzibianma_material_infos_wuzibianma_relation.material_info_type
const value = materialInfoType ? materialInfoType.split('-')[0] : ''
return h('span', value || '-')
}
},
{
title: '二级分类',
key: 'erjifenlei',
width: 120,
render: (h, params) => {
if (!params.row.inventory || !params.row.inventory.wuzibianma_material_infos_wuzibianma_relation) {
return h('span', '-')
}
const materialInfoType = params.row.inventory.wuzibianma_material_infos_wuzibianma_relation.material_info_type
let value = ''
if (materialInfoType) {
const parts = materialInfoType.split('-')
value = parts.length > 1 ? parts[1] : parts[0]
}
return h('span', value || '-')
}
},
{
title: '所属种类',
key: 'suoshuzhonglei',
width: 120,
render: (h, params) => {
if (!params.row.inventory || !params.row.inventory.wuzibianma_material_infos_wuzibianma_relation) {
return h('span', '-')
}
const fenleiDetail = params.row.inventory.wuzibianma_material_infos_wuzibianma_relation.fenlei_detail
const value = fenleiDetail ? fenleiDetail.name : ''
return h('span', value || '-')
}
},
{
title: '物资名称',
key: 'zichanmingcheng',
minWidth: 150,
render: (h, params) => {
return h('span', params.row.inventory ? params.row.inventory.zichanmingcheng : '-')
}
},
{
title: '物资型号',
key: 'guigexinghao',
width: 120,
render: (h, params) => {
return h('span', params.row.inventory ? params.row.inventory.guigexinghao : '-')
}
},
{
title: '物资规格',
key: 'wuziguige',
width: 120,
render: (h, params) => {
return h('span', params.row.inventory ? params.row.inventory.wuziguige : '-')
}
},
{
title: '单位',
key: 'jiliangdanwei',
width: 80,
render: (h, params) => {
return h('span', params.row.inventory ? params.row.inventory.jiliangdanwei : '-')
}
},
{
title: '原库存数量',
key: 'chushishuliang',
width: 120,
render: (h, params) => {
return h('span', params.row.inventory ? params.row.inventory.chushishuliang : '-')
}
},
{
title: '状态',
slot: 'status',
width: 100
},
{
title: '盘点人',
key: 'responsible_admin_name',
width: 120,
render: (h, params) => {
return h('span', params.row.responsible_admin ? params.row.responsible_admin.name : '-')
}
},
{
title: '盘点数量',
key: 'check_num',
width: 100
},
{
title: '盘点日期',
key: 'check_date',
width: 150
},
{
title: '照片',
slot: 'photos',
width: 150
},
{
title: '备注',
key: 'remark',
minWidth: 150,
tooltip: true
}
],
summaryModal: {
visible: false,
data: null,
signImageId: null,
signImage: null,
type: 1 // 默认为日常检查
}
}
},
watch: {
// 监听物资列表变化,确保选中状态正确显示
materialList: {
handler(newList, oldList) {
console.log('materialList 发生变化,新数据长度:', newList.length)
this.$nextTick(() => {
setTimeout(() => {
this.updateTableSelection()
}, 100)
})
},
deep: true
}
},
mounted() {
this.searchPlans()
this.searchHistoryPlans()
this.getFenlei()
this.getCangku()
this.getData()
},
methods: {
getStatusColor(status) {
const colors = {
0: 'red',
1: 'orange',
2: 'green'
}
return colors[status] || 'default'
},
getStatusText(status) {
const texts = {
0: '未开始',
1: '进行中',
2: '已完成'
}
return texts[status] || status
},
getInventoryStatusColor(status) {
const colors = {
0: 'red',
1: 'green'
}
return colors[status] || 'default'
},
getInventoryStatusText(status) {
const texts = {
0: '未盘点',
1: '已盘点'
}
return texts[status] || status
},
async searchPlans() {
this.planLoading = true
try {
const formData = new FormData()
formData.append('page', this.planSearch.pageIndex)
formData.append('page_size', this.planSearch.pageSize)
// 添加 wherein 参数,使用 filter 格式
formData.append('filter[0][key]', 'status')
formData.append('filter[0][op]', 'wherein')
formData.append('filter[0][value][0]', '0')
formData.append('filter[0][value][1]', '1')
// 只添加非空的搜索条件
if (this.planSearch.keyword) {
formData.append('keyword', this.planSearch.keyword)
}
// 确保日期范围有效且不为空
if (
this.planSearch.dateRange &&
this.planSearch.dateRange.length === 2 &&
this.planSearch.dateRange[0] &&
this.planSearch.dateRange[1]
) {
const formatDate = date => {
const d = new Date(date)
if (isNaN(d.getTime())) return null // 检查日期是否有效
const year = d.getFullYear()
const month = String(d.getMonth() + 1).padStart(2, '0')
const day = String(d.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`
}
const startDate = formatDate(this.planSearch.dateRange[0])
const endDate = formatDate(this.planSearch.dateRange[1])
// 只有当两个日期都有效时才添加过滤条件
// filter[0] 已被 wherein 占用,所以日期范围从 filter[1] 开始
if (startDate && endDate) {
formData.append('filter[1][key]', 'start_date')
formData.append('filter[1][op]', 'range')
formData.append('filter[1][value]', startDate + ',' + endDate)
}
}
const res = await getStocktakingPlanList(formData)
if (res && res.list) {
this.planList = res.list.data
this.planTotal = res.list.total
}
} catch (error) {
this.$Message.error('获取盘点计划列表失败')
console.error('获取盘点计划列表失败:', error)
} finally {
this.planLoading = false
}
},
resetPlanSearch() {
this.planSearch = {
keyword: '',
dateRange: [],
pageIndex: 1,
pageSize: 10
}
this.searchPlans()
},
handlePlanPageChange(page) {
this.planSearch.pageIndex = page
this.searchPlans()
},
handlePlanPageSizeChange(size) {
this.planSearch.pageSize = size
this.planSearch.pageIndex = 1
this.searchPlans()
},
showPlanModal(mode, plan) {
this.planModal.title = mode === 'new' ? '新建盘点计划' : '编辑盘点计划'
if (mode === 'edit' && plan) {
this.planModal.form = {
id: plan.id,
name: plan.name,
dateRange: [plan.start_date, plan.end_date],
type: plan.type,
remark: plan.remark
}
this.planModal.visible = true
} else {
this.planModal.form = {
id: '',
name: '',
dateRange: [],
type: 1, // 默认为日常检查
remark: ''
}
this.planModal.visible = true
this.$nextTick(() => {
if (this.$refs.planForm) {
this.$refs.planForm.resetFields()
}
})
}
},
handleDateClear() {
this.planModal.form.dateRange = null
this.$nextTick(() => {
this.planModal.form.dateRange = []
this.$refs.planForm.validateField('dateRange')
})
},
async handlePlanSubmit() {
this.$refs.planForm.validateField('dateRange', errorMessage => {
if (errorMessage) {
this.$Message.error(errorMessage)
return
}
})
this.$refs.planForm.validate(async valid => {
if (!valid) {
this.$Message.error('请完整填写必填项')
return
}
const { id, name, dateRange, type, remark } = this.planModal.form
const formatDate = date => {
const d = new Date(date)
const year = d.getFullYear()
const month = String(d.getMonth() + 1).padStart(2, '0')
const day = String(d.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`
}
// 获取当前计划选中的物资ID
const selectedMaterialIds = this.planMaterials[id] || []
// 构建参数对象
const params = {
name,
start_date: formatDate(dateRange[0]),
end_date: formatDate(dateRange[1]),
type,
material_infos_plan_links: selectedMaterialIds.map(materialId => ({
id: null, // 新建计划时都是新的关联记录
inventorys_id: materialId
}))
}
if (remark) params.remark = remark
if (id) params.id = id
console.log('提交计划参数:', params)
try {
await saveStocktakingPlan(params)
this.$Message.success('保存成功')
this.planModal.visible = false
this.$refs.planForm.resetFields()
this.searchPlans()
} catch (e) {
this.$Message.error('保存失败')
}
})
},
deletePlan(id) {
this.$confirm('删除计划的同时会删除盘点记录,确认是否删除?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(async() => {
await deleteStocktakingPlan({ id })
this.$message.success('删除成功')
this.searchPlans()
})
.catch(() => {})
},
async searchList() {
this.listLoading = true
try {
const params = {
page: this.listSearch.pageIndex,
page_size: this.listSearch.pageSize,
has_material_infos_plan_id: '0'
}
// 确保日期范围有效且不为空
if (
this.listSearch.dateRange &&
this.listSearch.dateRange.length === 2 &&
this.listSearch.dateRange[0] &&
this.listSearch.dateRange[1]
) {
const formatDate = date => {
const d = new Date(date)
if (isNaN(d.getTime())) return null // 检查日期是否有效
const year = d.getFullYear()
const month = String(d.getMonth() + 1).padStart(2, '0')
const day = String(d.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`
}
const startDate = formatDate(this.listSearch.dateRange[0])
const endDate = formatDate(this.listSearch.dateRange[1])
// 只有当两个日期都有效时才添加过滤条件
if (startDate && endDate) {
params['filter[0][key]'] = 'check_date'
params['filter[0][op]'] = 'range'
params['filter[0][value]'] = startDate + ',' + endDate
}
}
const res = await getStocktakingHistoryList(qs.stringify(params))
if (res) {
// 处理返回数据,可能是 res.data 或 res.list.data
if (res.list && res.list.data) {
this.inventoryList = res.list.data
this.listTotal = res.list.total || res.list.data.length
} else if (res.data) {
this.inventoryList = res.data
this.listTotal = res.total || res.data.length
} else {
this.inventoryList = []
this.listTotal = 0
}
}
} catch (error) {
this.$Message.error('获取盘点列表失败')
console.error('获取盘点列表失败:', error)
} finally {
this.listLoading = false
}
},
resetListSearch() {
this.listSearch = {
keyword: '',
status: '',
dateRange: [],
pageIndex: 1,
pageSize: 10
}
this.searchList()
},
handleListPageChange(page) {
this.listSearch.pageIndex = page
this.searchList()
},
handleListPageSizeChange(size) {
this.listSearch.pageSize = size
this.listSearch.pageIndex = 1
this.searchList()
},
handleHistoryTabChange(name) {
if (name === 'plan') {
this.searchHistoryPlans()
} else if (name === 'outside') {
this.searchList()
}
},
async searchHistoryPlans() {
this.historyPlanLoading = true
try {
const formData = new FormData()
formData.append('page', this.historyPlanSearch.pageIndex)
formData.append('page_size', this.historyPlanSearch.pageSize)
// 添加状态过滤 status:2
formData.append('filter[0][key]', 'status')
formData.append('filter[0][op]', 'eq')
formData.append('filter[0][value]', '2')
// 只添加非空的搜索条件
if (this.historyPlanSearch.keyword) {
formData.append('keyword', this.historyPlanSearch.keyword)
}
// 确保日期范围有效且不为空
if (
this.historyPlanSearch.dateRange &&
this.historyPlanSearch.dateRange.length === 2 &&
this.historyPlanSearch.dateRange[0] &&
this.historyPlanSearch.dateRange[1]
) {
const formatDate = date => {
const d = new Date(date)
if (isNaN(d.getTime())) return null // 检查日期是否有效
const year = d.getFullYear()
const month = String(d.getMonth() + 1).padStart(2, '0')
const day = String(d.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`
}
const startDate = formatDate(this.historyPlanSearch.dateRange[0])
const endDate = formatDate(this.historyPlanSearch.dateRange[1])
// 只有当两个日期都有效时才添加过滤条件
if (startDate && endDate) {
const filterIndex = this.historyPlanSearch.keyword ? 1 : 0
formData.append(`filter[${filterIndex}][key]`, 'start_date')
formData.append(`filter[${filterIndex}][op]`, 'range')
formData.append(`filter[${filterIndex}][value]`, startDate + ',' + endDate)
}
}
const res = await getStocktakingPlanList(formData)
if (res && res.list) {
this.historyPlanList = res.list.data
this.historyPlanTotal = res.list.total
}
} catch (error) {
this.$Message.error('获取历史盘点计划列表失败')
console.error('获取历史盘点计划列表失败:', error)
} finally {
this.historyPlanLoading = false
}
},
resetHistoryPlanSearch() {
this.historyPlanSearch = {
keyword: '',
dateRange: [],
pageIndex: 1,
pageSize: 10
}
this.searchHistoryPlans()
},
handleHistoryPlanPageChange(page) {
this.historyPlanSearch.pageIndex = page
this.searchHistoryPlans()
},
handleHistoryPlanPageSizeChange(size) {
this.historyPlanSearch.pageSize = size
this.historyPlanSearch.pageIndex = 1
this.searchHistoryPlans()
},
async viewInventoryDetail(row) {
this.detailModal.loading = true
this.detailModal.visible = true
this.detailModal.pageIndex = 1
// 先用列表行数据初始化基本信息
this.detailModal.data = {
id: row.id,
no: row.no,
planName: row.material_infos_plan ? row.material_infos_plan.name : '-',
area: row.material_info ? row.material_info.suozaicangku : '-',
executor: row.responsible_admin ? row.responsible_admin.name : '-',
startTime: row.material_infos_plan ? row.material_infos_plan.start_date : '-',
endTime: row.material_infos_plan ? row.material_infos_plan.end_date : '-',
status: row.status,
material_info: row.material_info || {},
history: []
}
try {
// 1. 获取物资详情
const materialRes = await request({
url: '/api/admin/material-infos/show',
method: 'get',
params: { id: row.material_info.id }
})
if (materialRes) {
this.detailModal.data.material_info = materialRes
}
// 2. 获取盘点历史记录
const params = {}
params['filter[0][key]'] = 'material_info_id'
params['filter[0][op]'] = 'eq'
params['filter[0][value]'] = row.material_info.id
params['page'] = this.detailModal.pageIndex || 1
params['page_size'] = this.detailModal.pageSize || 10
const res = await getStocktakingHistoryList(qs.stringify(params))
if (res) {
// 更新物资信息和历史记录数据
this.detailModal.data = {
...this.detailModal.data,
history: res.data || []
}
this.detailModal.total = res.data ? res.data.length : 0
}
} catch (error) {
this.$Message.error('获取盘点任务详情失败')
console.error('获取盘点任务详情失败:', error)
} finally {
this.detailModal.loading = false
}
},
async showInventorySelectModal(planId) {
this.materialModal.currentPlanId = planId
this.materialModal.visible = true
this.materialModal.pageIndex = 1
this.materialModal.selectedMaterialIds = new Set()
// 获取当前计划的已关联物资ID
try {
const formData = new FormData()
formData.append('page', 1)
formData.append('page_size', 9999) // 获取所有关联数据
formData.append('filter[0][key]', 'material_infos_plan_id')
formData.append('filter[0][op]', 'eq')
formData.append('filter[0][value]', planId)
const res = await getStocktakingPlanLinkList(formData)
if (res && res.list && res.list.data) {
// 从关联数据中提取已选中的 inventorys_id
console.log('API返回的关联数据:', res.list.data)
res.list.data.forEach(link => {
if (link.inventorys_id) {
// 确保ID类型一致转换为字符串
const inventorysId = String(link.inventorys_id)
this.materialModal.selectedMaterialIds.add(inventorysId)
// 保存关联记录的详细数据
this.materialModal.selectedMaterialData.set(inventorysId, {
id: link.id, // 关联记录的ID
inventorys_id: link.inventorys_id
})
console.log('添加选中ID:', inventorysId, '关联记录ID:', link.id)
}
})
console.log('已选中的物资ID:', this.materialModal.selectedMaterialIds)
console.log('选中物资的关联数据:', this.materialModal.selectedMaterialData)
}
} catch (error) {
console.error('获取计划关联数据失败:', error)
}
this.searchMaterials()
},
isSelected(item) {
const itemId = String(item.id)
const selected = this.materialModal.selectedMaterialIds.has(itemId)
console.log(
`检查物资 ${item.id} (类型: ${typeof item.id}, 转换后: ${itemId}) 是否选中:`,
selected
)
console.log('当前选中集合:', this.materialModal.selectedMaterialIds)
return selected
},
async toggleMaterialSelection(item, index) {
console.log('toggleMaterialSelection called', item, index)
const itemId = String(item.id)
// 更新选中状态
if (!this.isSelected(item)) {
console.log('Adding to plan:', itemId)
this.materialModal.selectedMaterialIds.add(itemId)
// 新添加的物资没有关联记录ID
this.materialModal.selectedMaterialData.set(itemId, {
id: null, // 新添加的没有ID
inventorys_id: item.id
})
item.selected = true
} else {
console.log('Removing from plan:', itemId)
// 检查是否是之前已选择的有关联记录ID
const materialData = this.materialModal.selectedMaterialData.get(itemId)
if (materialData && materialData.id) {
// 有关联记录ID需要确认删除
const confirmed = await this.$confirm('确认要将此物资移出计划吗?', '确认移出', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => true)
.catch(() => false)
if (confirmed) {
try {
// 调用删除接口
await deleteStocktakingPlanLink({ id: materialData.id })
this.$Message.success('已移出计划')
// 从选中状态中移除
this.materialModal.selectedMaterialIds.delete(itemId)
this.materialModal.selectedMaterialData.delete(itemId)
item.selected = false
} catch (error) {
this.$Message.error('移出计划失败')
console.error('删除关联记录失败:', error)
return // 如果删除失败,不更新界面状态
}
} else {
// 用户取消了删除操作,不做任何处理
return
}
} else {
// 没有关联记录ID直接移除
this.materialModal.selectedMaterialIds.delete(itemId)
this.materialModal.selectedMaterialData.delete(itemId)
item.selected = false
}
}
// 更新表格选中状态
this.$nextTick(() => {
this.updateTableSelection()
})
},
async searchMaterials() {
this.materialModal.loading = true
this.materialModal.isInitialLoad = true // 重置标志
try {
const res = await index({
page_size: this.materialModal.pageSize,
page: this.materialModal.pageIndex,
table_name: 'inventorys',
sort_type: 'DESC',
sort_name: 'wuzibianma',
fenlei: this.materialModal.fenlei,
wuzizhuangtai: this.materialModal.wuzizhuangtai,
chanquanxinxi: this.materialModal.chanquanxinxi,
chubeifangshi: this.materialModal.chubeifangshi,
suozaicangku: this.materialModal.suozaicangku,
start_rukuriqi: this.materialModal.rukuriqi ? this.materialModal.rukuriqi[0] : '',
end_rukuriqi: this.materialModal.rukuriqi ? this.materialModal.rukuriqi[1] : '',
start_shengchanriqi: this.materialModal.shengchanriqi
? this.materialModal.shengchanriqi[0]
: '',
end_shengchanriqi: this.materialModal.shengchanriqi
? this.materialModal.shengchanriqi[1]
: '',
dengjifenlei: this.materialModal.dengjifenlei,
filter: [
{
key: 'zichanmingcheng',
op: 'like',
value: this.materialModal.keyword
}
]
})
if (res && res.list) {
this.materialList = res.list.data.map(item => {
const itemId = String(item.id)
const isSelected = this.materialModal.selectedMaterialIds.has(itemId)
return {
...item,
selected: isSelected,
_checked: isSelected, // 尝试不同的选中标记
checked: isSelected // 再尝试另一种标记
}
})
this.materialModal.total = res.list.total
this.handleDataChange()
// 选中状态已在 showInventorySelectModal 中初始化
console.log('当前选中的物资ID:', this.materialModal.selectedMaterialIds)
console.log(
'物资列表数据:',
this.materialList.map(item => ({
id: item.id,
idType: typeof item.id,
selected: item.selected,
name: item.zichanmingcheng
}))
)
// 强制重新渲染表格
this.materialModal.tableKey++
// 手动设置表格的选中状态
this.$nextTick(() => {
// 延迟一点时间确保DOM完全渲染
setTimeout(() => {
this.updateTableSelection()
// 强制更新组件以确保按钮状态正确
this.$forceUpdate()
}, 100)
})
// 同时尝试通过事件触发选中状态
this.$nextTick(() => {
setTimeout(() => {
this.triggerSelectionByEvent()
}, 200)
})
// 最后尝试直接操作DOM
this.$nextTick(() => {
setTimeout(() => {
this.forceCheckboxSelection()
}, 400)
})
}
} finally {
this.materialModal.loading = false
}
},
async batchAddMaterials() {
const selection = this.materialList.filter(m => m.selected)
if (selection.length === 0) {
this.$Message.warning('请至少选择一项物资')
return
}
const planId = this.materialModal.currentPlanId
if (!this.planMaterials[planId]) {
this.planMaterials[planId] = []
}
selection.forEach(material => {
if (!this.planMaterials[planId].includes(material.id)) {
this.planMaterials[planId].push(material.id)
}
})
this.$Message.success(`已批量加入 ${selection.length} 项物资`)
this.searchMaterials()
},
async batchRemoveMaterials() {
const selection = this.materialList.filter(m => m.selected)
if (selection.length === 0) {
this.$Message.warning('请至少选择一项物资')
return
}
const planId = this.materialModal.currentPlanId
if (this.planMaterials[planId]) {
this.planMaterials[planId] = this.planMaterials[planId].filter(
id => !selection.some(m => m.id === id)
)
}
this.$Message.success(`已批量移出 ${selection.length} 项物资`)
this.searchMaterials()
},
resetMaterialSearch() {
this.materialModal.keyword = ''
this.materialModal.fenlei = ''
this.materialModal.wuzizhuangtai = ''
this.materialModal.chanquanxinxi = ''
this.materialModal.chubeifangshi = ''
this.materialModal.suozaicangku = ''
this.materialModal.rukuriqi = ''
this.materialModal.shengchanriqi = ''
this.materialModal.dengjifenlei = ''
this.materialModal.pageIndex = 1
this.searchMaterials()
},
handleMaterialPageChange(page) {
console.log('页面切换到:', page)
this.materialModal.pageIndex = page
this.searchMaterials()
},
handleMaterialPageSizeChange(size) {
this.materialModal.pageSize = size
this.materialModal.pageIndex = 1
this.searchMaterials()
},
async handleMaterialSubmit() {
const planId = this.materialModal.currentPlanId
if (!planId) {
this.$Message.error('未找到计划ID')
return
}
// 构建新的数据结构
const materialInfosPlanLinks = []
this.materialModal.selectedMaterialData.forEach((data, inventorysId) => {
materialInfosPlanLinks.push({
id: data.id, // 如果是新添加的为null已存在的有ID
inventorys_id: data.inventorys_id
})
})
console.log('提交的数据结构:', materialInfosPlanLinks)
// 构建参数对象
const params = {
id: planId,
material_infos_plan_links: materialInfosPlanLinks
}
console.log('提交物资关联参数:', params)
try {
await saveStocktakingPlan(params)
this.$Message.success('物资关联成功')
this.handleMaterialModalClose()
this.searchPlans()
} catch (e) {
this.$Message.error('物资关联失败')
console.error('提交失败:', e)
}
},
// 处理物资选择弹窗关闭
handleMaterialModalClose() {
this.materialModal.visible = false
// 清除所有数据和状态
this.materialModal.currentPlanId = ''
this.materialModal.selectedMaterialIds = new Set()
this.materialModal.selectedMaterialData = new Map()
this.materialModal.pageIndex = 1
this.materialModal.keyword = ''
this.materialModal.fenlei = ''
this.materialModal.wuzizhuangtai = ''
this.materialModal.chanquanxinxi = ''
this.materialModal.chubeifangshi = ''
this.materialModal.suozaicangku = ''
this.materialModal.rukuriqi = ''
this.materialModal.shengchanriqi = ''
this.materialModal.dengjifenlei = ''
this.materialModal.isUpdatingSelection = false
this.materialModal.tableKey = 0
this.materialList = []
this.materialModal.total = 0
console.log('物资选择弹窗已关闭,数据已清除')
},
handleDetailPageChange(page) {
this.detailModal.pageIndex = page
this.viewInventoryDetail(this.detailModal.data.id)
},
handleDetailPageSizeChange(size) {
this.detailModal.pageSize = size
this.detailModal.pageIndex = 1
this.viewInventoryDetail(this.detailModal.data.id)
},
previewImage(url) {
this.previewUrl = url
},
closePreview() {
this.previewUrl = ''
},
getPlanProgress(row) {
// 根据状态值判断进度
const status = row.status
if (status === 0) {
// 未开始
return 0
} else if (status === 1) {
// 进行中
return 50
} else if (status === 2) {
// 已完成
return 100
}
return 0
},
viewPlanDetail(row) {
this.planDetailModal.visible = true
this.planDetailModal.data = row
this.planDetailModal.pageIndex = 1
this.loadPlanDetailData()
},
async loadPlanDetailData() {
this.planDetailModal.loading = true
try {
const params = {
page: this.planDetailModal.pageIndex,
page_size: this.planDetailModal.pageSize,
'filter[0][key]': 'material_infos_plan_id',
'filter[0][op]': 'eq',
'filter[0][value]': this.planDetailModal.data.id
}
console.log('获取计划详情参数:', params)
const res = await getStocktakingPlanLinkList(qs.stringify(params))
if (res && res.list) {
this.planDetailModal.inventoryList = res.list.data
this.planDetailModal.total = res.list.total
console.log('计划详情数据:', res.list.data)
}
} catch (e) {
this.$Message.error('获取盘点物资列表失败')
console.error('获取计划详情失败:', e)
} finally {
this.planDetailModal.loading = false
}
},
handlePlanDetailPageChange(page) {
this.planDetailModal.pageIndex = page
this.loadPlanDetailData()
},
handlePlanDetailPageSizeChange(size) {
this.planDetailModal.pageSize = size
this.planDetailModal.pageIndex = 1
this.loadPlanDetailData()
},
showSummaryModal(row) {
// 从原始列表数据中查找完整的计划信息
console.log('this.planList', this.historyPlanList)
const planData = this.historyPlanList.find(plan => plan.id === row.id)
if (!planData) {
this.$Message.error('未找到计划数据')
return
}
this.summaryModal.data = {
id: planData.id,
name: planData.name,
planStart: planData.start_date,
planEnd: planData.end_date,
actualStart: planData.act_start_date || '-',
actualEnd: planData.act_end_date || '-',
planCount: planData.chart_total || '-',
actualCount: planData.chart_done || '-'
}
this.summaryModal.signImageId = planData.sign_id || null
this.summaryModal.signImage = planData.sign ? planData.sign.url : null
this.summaryModal.visible = true
},
beforeSignUpload(file) {
// 可加图片类型/大小校验
return true
},
handleSignUpload(response) {
// 假设 response.url 是图片地址
this.summaryModal.signImageId = response.id
this.summaryModal.signImage = response.url
},
handleMoreCommand(command, row) {
if (command === 'edit') {
this.showPlanModal('edit', row)
} else if (command === 'delete') {
this.deletePlan(row.id)
} else if (command === 'view') {
this.viewPlanDetail(row)
}
},
async handleSummarySubmit() {
if (!this.summaryModal.signImageId) {
this.$Message.warning('请上传签字图片')
return
}
try {
const params = {
id: this.summaryModal.data.id,
sign_id: this.summaryModal.signImageId
}
await saveStocktakingPlan(params)
this.$Message.success('提交成功')
this.summaryModal.visible = false
this.searchHistoryPlans() // 刷新列表
} catch (error) {
this.$Message.error('提交失败:' + (error.message || '未知错误'))
}
},
// 获取仓库
async getCangku() {
const res = await baseFormIndex({
page_size: 999,
page: 1,
table_name: 'materialstorages',
sort_name: 'sort',
sort_type: 'ASC',
filter: [
{
key: 'shifouzili',
op: 'eq',
value: '是'
}
]
})
this.cangkuList = res.data
},
// 获取数据字典
async getData() {
const res = await getparameteritemMore({
'number[0]': 'materials_status', // 物资状态
'number[1]': 'material_reserve', // 储备方式
'number[2]': 'materials_property', // 产权信息
'number[3]': 'dengjifenlei' // 等级分类
})
for (var k in this.paraOptions) {
res.map(item => {
if (item.number === k) {
this.paraOptions[k] = item.detail
}
})
}
},
async getFenlei() {
const res = await getFenleilist({
tree: 1,
sort_type: 'ASC',
sort_name: 'sort'
})
this.fenleiList = this.removeEmptyChildren(res)
},
changeFenlei(e, row) {
console.log('e', e)
if (e) {
this.materialModal.fenlei = e[e.length - 1]
} else {
this.materialModal.fenlei = ''
}
},
// 移除children=[]
removeEmptyChildren(node) {
if (Array.isArray(node)) {
return node.map(child => {
if (child.children) {
// 递归处理子节点
child.children = this.removeEmptyChildren(child.children)
// 若处理后 children 为空,删除该属性
if (child.children.length === 0) {
delete child.children
}
}
return child
})
}
return []
},
// filterSpans
getSpanArr(data) {
// 生成合并规则数组(保持不变)
this.spanArr = []
this.position = 0
data.forEach((item, index) => {
if (index === 0) {
this.spanArr.push(1)
this.position = 0
} else {
if (
item.wuzibianma ===
data[this.position].wuzibianma_material_infos_wuzibianma_relation.wuzibianma
) {
this.spanArr[this.position] += 1
this.spanArr.push(0)
} else {
this.spanArr.push(1)
this.position = index
}
}
})
},
objectSpanMethod({ row, column, rowIndex, columnIndex }) {
// 通过列索引范围判断是否需要合并
if (columnIndex >= this.mergeColumnRange.start && columnIndex <= this.mergeColumnRange.end) {
const _row = this.spanArr[rowIndex]
const _col = _row > 0 ? 1 : 0
return {
rowspan: _row,
colspan: _col
}
}
// 其他列保持默认
return {
rowspan: 1,
colspan: 1
}
},
handleDataChange() {
this.getSpanArr(this.materialList)
},
selectionChange(e) {
console.log('selectionChange', e, '是否正在程序更新:', this.materialModal.isUpdatingSelection)
// 如果是程序更新选中状态,忽略此事件
if (this.materialModal.isUpdatingSelection) {
console.log('忽略程序触发的选中变化事件')
return
}
// 更新选中状态集合 - 支持跨页选择
const planId = this.materialModal.currentPlanId
if (planId) {
// 获取当前页面所有行的ID
const currentPageIds = this.materialList.map(item => String(item.id))
// 从选中集合中移除当前页面的所有ID
currentPageIds.forEach(id => {
this.materialModal.selectedMaterialIds.delete(id)
})
// 添加新选中的项(来自当前页面)
e.forEach(item => {
const itemId = String(item.id)
this.materialModal.selectedMaterialIds.add(itemId)
// 如果不存在关联数据,添加新的(表示新选中的)
if (!this.materialModal.selectedMaterialData.has(itemId)) {
this.materialModal.selectedMaterialData.set(itemId, {
id: null, // 新选中的没有关联记录ID
inventorys_id: item.id
})
}
console.log('通过表格选中添加ID:', itemId)
})
// 更新当前页面数据的selected状态
this.materialList.forEach(item => {
const itemId = String(item.id)
item.selected = this.materialModal.selectedMaterialIds.has(itemId)
})
console.log('更新后的选中集合:', this.materialModal.selectedMaterialIds)
}
},
// 为 xy-table 提供选中状态判断
getSelectedRows() {
return this.materialList.filter(item =>
this.materialModal.selectedMaterialIds.has(String(item.id))
)
},
// 通过事件方式触发选中状态
triggerSelectionByEvent() {
console.log('尝试通过事件方式触发选中状态')
const selectedRows = this.getSelectedRows()
console.log(
'应该选中的行:',
selectedRows.map(row => ({ id: row.id, name: row.zichanmingcheng }))
)
if (selectedRows.length > 0) {
// 模拟选中事件
this.materialModal.isUpdatingSelection = true
this.selectionChange(selectedRows)
setTimeout(() => {
this.materialModal.isUpdatingSelection = false
}, 100)
}
},
// 通过DOM操作直接勾选复选框
forceCheckboxSelection() {
console.log('尝试通过DOM操作直接勾选复选框')
this.$nextTick(() => {
setTimeout(() => {
// 查找所有复选框
const checkboxes = document.querySelectorAll('.el-table .el-checkbox__input')
console.log('找到复选框数量:', checkboxes.length)
this.materialList.forEach((row, index) => {
const itemId = String(row.id)
if (this.materialModal.selectedMaterialIds.has(itemId)) {
// 找到对应的复选框(跳过表头的复选框)
const checkbox = checkboxes[index + 1]
if (checkbox && !checkbox.classList.contains('is-checked')) {
console.log('直接点击复选框:', itemId)
checkbox.click()
}
}
})
}, 300)
})
},
// 更新表格选中状态
updateTableSelection(retryCount = 0) {
console.log(
`开始更新表格选中状态 (重试次数: ${retryCount})当前选中ID:`,
this.materialModal.selectedMaterialIds
)
// 尝试多种方式获取表格引用
let table = null
if (this.$refs.materialTable) {
console.log('materialTable ref 存在')
// 方式1直接通过 $refs.table
if (this.$refs.materialTable.$refs && this.$refs.materialTable.$refs.table) {
table = this.$refs.materialTable.$refs.table
console.log('通过 $refs.table 找到表格')
}
// 方式2通过子组件
else if (
this.$refs.materialTable.$children &&
this.$refs.materialTable.$children.length > 0
) {
for (let child of this.$refs.materialTable.$children) {
if (child.$refs && child.$refs.table) {
table = child.$refs.table
console.log('通过子组件找到表格')
break
}
// 深度查找
if (child.$children && child.$children.length > 0) {
for (let grandChild of child.$children) {
if (grandChild.$refs && grandChild.$refs.table) {
table = grandChild.$refs.table
console.log('通过孙子组件找到表格')
break
}
}
if (table) break
}
}
}
// 方式3通过 $el 查找
else if (this.$refs.materialTable.$el) {
const tableEl = this.$refs.materialTable.$el.querySelector('.el-table')
if (tableEl && tableEl.__vue__) {
table = tableEl.__vue__
console.log('通过 DOM 元素找到表格')
}
}
}
if (table && typeof table.clearSelection === 'function') {
console.log('找到表格组件,开始设置选中状态')
// 设置标志,表示正在程序更新选中状态
this.materialModal.isUpdatingSelection = true
// 清除所有选中状态
table.clearSelection()
// 设置选中状态
let selectedCount = 0
this.materialList.forEach(row => {
const rowId = String(row.id)
if (this.materialModal.selectedMaterialIds.has(rowId)) {
console.log('设置行选中:', rowId, row.zichanmingcheng)
table.toggleRowSelection(row, true)
selectedCount++
}
})
console.log(`当前页面设置了 ${selectedCount} 行选中状态`)
// 重置标志
setTimeout(() => {
this.materialModal.isUpdatingSelection = false
console.log('表格选中状态更新完成,重置标志')
}, 200)
} else {
console.log('未找到表格组件引用或表格方法不可用')
// 最多重试3次
if (retryCount < 3) {
console.log(`将在500ms后进行第${retryCount + 1}次重试`)
setTimeout(() => {
this.updateTableSelection(retryCount + 1)
}, 500)
} else {
console.error('重试3次后仍未找到表格组件放弃更新选中状态')
}
}
}
}
}
</script>
<style scoped lang="scss">
.code {
position: absolute;
left: 0;
top: 0;
background: rgba(0, 0, 0, 0.5);
width: 100%;
height: 100%;
z-index: 9999;
}
#qrCode {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.content-wrapper {
background-color: #fff;
padding: 20px;
border-radius: 8px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.page-header {
margin-bottom: 20px;
padding-bottom: 15px;
border-bottom: 1px solid #e8e8e8;
display: flex;
justify-content: space-between;
align-items: center;
}
.page-title {
font-size: 16px;
font-weight: 600;
color: #333;
margin: 0;
}
.search-filters {
padding: 15px 0;
margin-bottom: 20px;
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 15px 20px;
}
.filter-item {
display: flex;
align-items: center;
gap: 8px;
}
.pagination-container {
display: flex;
justify-content: flex-end;
margin-top: 20px;
padding-top: 15px;
border-top: 1px solid #f0f0f0;
}
.el-pagination {
padding: 0;
font-weight: normal;
.el-pagination__sizes {
margin-right: 16px;
}
.el-pagination__jump {
margin-left: 16px;
}
.el-pagination__total {
margin-right: 16px;
}
.btn-prev,
.btn-next {
background: #fff;
border: 1px solid #dcdfe6;
&:hover {
color: #409eff;
}
}
.el-pager li {
background: #fff;
border: 1px solid #dcdfe6;
&:hover {
color: #409eff;
}
&.active {
background-color: #409eff;
color: #fff;
border-color: #409eff;
}
}
}
.material-search {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 10px;
margin-bottom: 10px;
}
.ivu-modal {
.ivu-modal-content {
width: 900px;
max-width: 90vw;
}
.ivu-modal-header {
padding: 16px 24px;
border-bottom: 1px solid #e8eaec;
.ivu-modal-header-inner {
font-size: 16px;
font-weight: 500;
color: #17233d;
}
}
.ivu-modal-body {
padding: 24px;
}
}
.ivu-table {
.ivu-table-cell {
padding: 8px 16px;
}
.ivu-table-header {
th {
background: #f8f8f9;
font-weight: 600;
color: #17233d;
}
}
.ivu-table-tbody {
tr {
&:hover {
td {
background: #f5f7fa;
}
}
}
}
}
.detail-content {
padding: 20px;
.detail-header {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
margin-bottom: 30px;
.detail-item {
.label {
font-weight: bold;
color: #666;
margin-right: 10px;
}
.value {
color: #333;
}
}
}
.material-info-section {
margin-bottom: 30px;
h3 {
margin: 0 0 15px 0;
font-size: 16px;
color: #17233d;
}
.material-info-content {
background: #f8f8f9;
padding: 20px;
border-radius: 8px;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
.info-item {
.label {
font-weight: bold;
color: #666;
margin-right: 10px;
}
.value {
color: #333;
}
}
}
}
.history-section {
h3 {
margin: 0 0 15px 0;
font-size: 16px;
color: #17233d;
}
}
}
.photo-list {
display: flex;
gap: 8px;
align-items: center;
.photo-item {
width: 40px;
height: 40px;
border-radius: 4px;
overflow: hidden;
cursor: pointer;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
.photo-more {
color: #666;
font-size: 12px;
}
}
.image-preview-modal {
position: fixed;
z-index: 2000;
left: 0;
top: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.7);
display: flex;
align-items: center;
justify-content: center;
}
.image-preview-large {
max-width: 90vw;
max-height: 90vh;
border-radius: 8px;
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.3);
background: #fff;
}
.plan-detail-content {
padding: 20px;
.detail-header {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
margin-bottom: 30px;
.detail-item {
.label {
font-weight: bold;
color: #666;
margin-right: 10px;
}
.value {
color: #333;
}
}
}
.inventory-list-section {
margin-bottom: 30px;
h3 {
margin: 0 0 15px 0;
font-size: 16px;
color: #17233d;
}
}
}
.summary-table {
width: 100%;
border-collapse: collapse;
font-size: 16px;
background: #fff;
margin-bottom: 16px;
}
.summary-table td {
border: 1px solid #333;
padding: 14px 16px;
min-width: 120px;
background: #fff;
color: #222;
font-weight: normal;
}
.summary-table .sign-cell {
height: 80px;
min-height: 80px;
line-height: 80px;
}
.summary-table td:first-child {
background: #fff;
color: #111;
font-weight: bold;
width: 160px;
}
.selector-item {
margin-right: 10px;
margin-bottom: 5px;
}
</style>