lanan-system-vue/src/views/repair/stockOperate/Components/SoIndex.vue
2024-11-21 15:19:48 +08:00

672 lines
25 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div>
<!-- 搜索 -->
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="90px">
<el-form-item :label="soByType ? '采购时间' : !isBack ? '领料时间' : '退料时间'" prop="searchTimeArray">
<el-date-picker
value-format="yyyy-MM-dd HH:mm:ss"
v-model="queryParams.searchTimeArray"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期">
</el-date-picker>
</el-form-item>
<el-form-item v-if="soByType && !goodsYes" label="供应商" prop="supplierId">
<SupplierChoose v-model="queryParams.supplier"/>
</el-form-item>
<el-form-item v-if="goodsYes" label="关键字" prop="query">
<el-input v-model="queryParams.query" style="width: 18rem" placeholder="请输入单号、商品名称或编码"/>
</el-form-item>
<el-form-item v-else label="单据号" prop="query">
<el-input v-model="queryParams.query" style="width: 18rem" placeholder="请输入单号、备注"/>
</el-form-item>
<el-form-item v-if="soByType" label="状态" prop="soStatus">
<el-select v-model="queryParams.soStatus" clearable>
<el-option v-for="item in getStatus"
:key="item.value"
:label="item.label"
:value="item.value"/>
</el-select>
</el-form-item>
<el-form-item v-if="!soByType" :label="!isBack ? '领料人' : '退料人'" prop="userId">
<StaffChoose v-model="queryParams.user" @selected="getStaff"/>
</el-form-item>
<el-form-item v-if="!isBack" :label="soByType ? '采购门店' : '领料门店'" prop="corpId">
<CorpChoose v-model="queryParams.corp" @selected="getCompany"/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 操作 -->
<el-row :gutter="10" class="mb8">
<!-- <el-col :span="1.5">-->
<!-- <el-button type="primary" plain icon="el-icon-download" size="mini"-->
<!-- >导出-->
<!-- </el-button>-->
<!-- </el-col>-->
<right-toolbar :showSearch.sync="showSearch"></right-toolbar>
</el-row>
<!-- 急件 -->
<!-- <el-table v-if="goodsYes" v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">-->
<!-- <el-table-column label="序号" align="center">-->
<!-- <template scope="scope">-->
<!-- <span>{{ scope.$index + 1 }}</span>-->
<!-- </template>-->
<!-- </el-table-column>-->
<!-- <el-table-column label="单号" align="center" prop="soId" width="200"/>-->
<!-- <el-table-column label="商品名称" align="center" width="180" prop="name"/>-->
<!-- <el-table-column label="规格" align="center" width="180" prop="name"/>-->
<!-- <el-table-column label="商品编码" align="center" width="180" prop="name"/>-->
<!-- <el-table-column label="所属分类" align="center" width="150" prop="name"/>-->
<!-- <el-table-column label="数量" align="center" width="150" prop="name"/>-->
<!-- <el-table-column label="单位" align="center" width="150" prop="name"/>-->
<!-- <el-table-column label="成本" align="center" width="150" prop="name"/>-->
<!-- <el-table-column label="供应商" align="center" width="180" prop="name"/>-->
<!-- <el-table-column label="仓库" align="center" width="150" prop="name"/>-->
<!-- <el-table-column label="状态" align="center" width="150" prop="name"/>-->
<!-- <el-table-column label="时间" align="center" width="150" prop="name"/>-->
<!-- <el-table-column label="门店" align="center" width="180" prop="name"/>-->
<!-- <el-table-column label="操作" align="center" width="180" fixed="right">-->
<!-- <template v-slot="scope">-->
<!-- <el-button size="mini" type="text" icon="el-icon-edit"-->
<!-- >审核-->
<!-- </el-button>-->
<!-- </template>-->
<!-- </el-table-column>-->
<!-- </el-table>-->
<!-- 采购/领料 -->
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
<el-table-column label="序号" align="center">
<template scope="scope">
<span>{{ scope.$index + 1 }}</span>
</template>
</el-table-column>
<el-table-column label="单号" align="center" prop="soNo" width="200"/>
<el-table-column label="数量" align="center" prop="itemCount" width="150"/>
<el-table-column label="金额" align="center" prop="totalPrice" width="150"/>
<el-table-column :label="soByType ? '采购员' : !isBack ? '领料人' : '退料人'" align="center" prop="userName"
width="150"/>
<el-table-column v-if="soByType" label="供应商" align="center" prop="supplierName" width="200"/>
<el-table-column :label="soByType ? '入库时间' : !isBack ? '领料时间' : '退料时间'" align="center" prop="soTime"
width="150"/>
<el-table-column label="登记时间" align="center" prop="createTime" width="150">
<template slot-scope="scope">
{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}
</template>
</el-table-column>
<el-table-column v-if="!isBack" label="门店" align="center" prop="corpName" width="180"/>
<el-table-column v-if="soByType" label="状态" align="center" prop="soStatus" width="150">
<template slot-scope="scope">
<dict-tag :type="DICT_TYPE.REPAIR_SO_STATUS" :value="scope.row.soStatus"/>
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" width="180"/>
<el-table-column label="操作" fixed="right" width="180" align="center">
<template v-slot="scope">
<el-button size="mini" type="text" icon="el-icon-view" @click="handleShow(scope.row)"
>查看
</el-button>
<el-button @click="handleInWares(scope.row)" v-if="scope.row.soStatus === '02'" size="mini" type="text"
icon="el-icon-edit-outline"
>入库
</el-button>
<el-button size="mini" type="text" icon="el-icon-close" @click="handleVoidSo(scope.row)"
>作废
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<pagination @pagination="pageSo" style="margin-bottom: 3rem" v-show="total > 0" :total="total"
:page.sync="queryParams.pageNo"
:limit.sync="queryParams.pageSize"
/>
<SoShow :so-by-type="soByType" :is-back="isBack" ref="soShow"/>
<el-dialog title="入库" :visible.sync="dialogVisible" width="80%" v-dialogDrag append-to-body>
<el-form :inline="true">
<el-form-item label="关键字">
<el-input v-model="inItemsQuery" placeholder="名称、规格、编码"/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="searchByQuery">搜索</el-button>
<el-button icon="el-icon-refresh" @click=resetByQuery>重置</el-button>
</el-form-item>
</el-form>
<el-collapse>
<el-collapse-item v-for="([key, value], index) in inItems" :title="key + `(${value.length})`">
<el-table v-loading="inLoading" :ref="`tableRef_${key}`" :data="value" :stripe="true"
:show-overflow-tooltip="true"
@selection-change="selectRow"
@cell-mouse-enter="handleCellEnter"
@cell-mouse-leave="handleCellLeave"
@cell-click="handleCellClick"
>
<el-table-column type="selection" width="55" align="center"/>
<el-table-column label="商品名称" align="center" prop="wares.name"/>
<el-table-column label="规格" align="center" width="180" prop="wares.model">
<div class="item" slot-scope="scope">
<el-input @blur="save(scope.row)" class="item__input" v-model="scope.row.wares.model"
placeholder="请输入规格"></el-input>
<span class="item__txt">{{ scope.row.wares.model }}</span>
</div>
</el-table-column>
<el-table-column label="分类" align="center" width="180" prop="wares.type">
<div class="item" slot-scope="scope">
<el-select class="item__input" clearable ref="selectTree" v-model="scope.row.wares.type"
@change="save(scope.row)">
<el-option v-for="server in optionData(serverList)"
:key="server.value"
:label="server.label"
:value="server.value" style="display: none"/>
<el-tree class="item__input" ref="selectedTree"
:data="serverList"
:props="treeProps"
highlight-current
@node-click="handleNodeClick($event, scope.row)"
:expand-on-click-node="expandOnClickNode"
default-expand-all/>
</el-select>
<span class="item__txt">{{ getTypeById(scope.row.wares.type) }}</span>
</div>
</el-table-column>
<el-table-column label="商品编码" align="center" width="180" prop="wares.code">
<div class="item" slot-scope="scope">
<el-input @blur="save(scope.row)" class="item__input" v-model="scope.row.wares.code"
placeholder="请输入内容"></el-input>
<span class="item__txt">{{ scope.row.wares.code }}</span>
</div>
</el-table-column>
<el-table-column label="仓库" align="center" width="150" prop="wares.warehouse">
<div class="item" slot-scope="scope">
<WarehouseChoose @input-blur="save(scope.row)" class="item__input" v-model="scope.row.wares.ware"
/>
<span class="item__txt">{{ scope.row.wares?.ware?.name }}</span>
</div>
</el-table-column>
<el-table-column label="库存" align="center" width="150" prop="wares.stock"/>
<el-table-column label="单位" align="center" width="150" prop="wares.unit">
<div class="item" slot-scope="scope">
<el-select class="item__input" v-model="scope.row.wares.unit" @blur="save(scope.row)">
<el-option v-for="dict in getDictDatasToType(DICT_TYPE.REPAIR_UNIT)" :key="dict.value"
:label="dict.label"
:value="dict.value"/>
</el-select>
<span class="item__txt">
<dict-tag :type="DICT_TYPE.REPAIR_UNIT" v-model="scope.row.wares.unit"/>
</span>
</div>
</el-table-column>
<el-table-column label="进价" align="center" width="150" prop="wares.purPrice">
<div class="item" slot-scope="scope">
<el-input @blur="save(scope.row)" class="item__input" v-model="scope.row.wares.purPrice"
placeholder="请输入内容"></el-input>
<span class="item__txt">{{ scope.row.wares.purPrice }}</span>
</div>
</el-table-column>
<el-table-column label="售价" align="center" width="150" prop="wares.price">
<div class="item" slot-scope="scope">
<el-input @blur="save(scope.row)" class="item__input" v-model="scope.row.wares.price"
placeholder="请输入内容"></el-input>
<span class="item__txt">{{ scope.row.wares.price }}</span>
</div>
</el-table-column>
<el-table-column label="采购数量" align="center" prop="goodsCount" width="150"/>
<el-table-column label="入库数量" align="center" prop="inCount" width="150">
<div class="item" slot-scope="scope">
<el-input @blur="save(scope.row)" class="item__input" v-model="scope.row.inCount"/>
<span class="item__txt">{{ scope.row.inCount }}</span>
</div>
</el-table-column>
</el-table>
</el-collapse-item>
</el-collapse>
<div slot="footer" class="dialog-footer">
<el-button type="primary" :disabled="allSelectRows.length === 0" @click="doInWares">确定</el-button>
<el-button @click="dialogVisible = false">取消</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import SupplierChoose from "@/views/repair/Components/SupplierChoose.vue";
import CorpChoose from "@/views/repair/Components/CorpChoose.vue";
import StaffChoose from "@/views/repair/Components/StaffChoose.vue";
import {DICT_TYPE} from "@/utils/dict";
import {getRepairSoPage, voidSo, getRepairSoById, inWare} from "@/api/repair/stockOperate/stockOperate";
import SoShow from "@/views/repair/stockOperate/Components/SoSow.vue";
import {getRepairSoiByIds, getMapBySoIdAndQuery} from "@/api/repair/stockOperate/stockOperateItem";
import {createUniqueCodeByHead} from "@/utils/createUniqueCode";
import WarehouseChoose from "@/views/repair/Components/WarehouseChoose.vue";
import {getBaseTypeList} from "@/api/base/type";
export default {
name: "SoIndex",
computed: {
getStatus() {
const data = this.getDictDatas(DICT_TYPE.REPAIR_SO_STATUS)
return data.filter(item => item.label.toString().indexOf("领料") === -1)
}
},
components: {
WarehouseChoose,
SoShow,
StaffChoose,
SupplierChoose,
CorpChoose
},
props: {
soByType: {
type: Boolean,
defaultValue: true,
required: true
},
goodsYes: {
type: Boolean,
defaultValue: false,
required: false
},
isBack: {
type: Boolean
}
},
watch: {
'queryParams.supplier'(val) {
this.queryParams.supplierId = val ? val.id : null
},
'queryParams.corp'(val) {
this.queryParams.corpId = val ? val.id : null
},
'queryParams.user'(val) {
this.queryParams.userId = val ? val.id : null
}
},
data() {
return {
queryParams: {
pageNo: 1,
pageSize: 10,
searchTimeArray: [],
soNo: null,
supplier: null,
supplierId: null,
supplierName: null,
soStatus: null,
corp: null,
corpId: null,
user: null,
userId: null,
userName: null,
soType: this.soByType ? "01" : "02",
purchaseType: this.goodsYes ? "02" : "01",
goodsType: this.goodsYes ? "1" : "0"
},
formData: {
remark: null,
id: null,
soStatus: "06"
},
showSearch: true,
list: [],
loading: false,
total: 0,
dialogVisible: false,
inItems: [],
inItemsQuery: null,
inLoading: false,
selectRows: [],
inWaresFormData: {
id: null,
soiList: [],
soNo: null
},
editProp: ['inCount', 'wares.model', 'wares.type', 'wares.code', 'wares.warehouse', 'wares.unit', 'wares.purPrice', 'wares.price'],
clickCellMap: {},
tableKey: 0,
soId: null,
expandOnClickNode: true,
serverList: [],
treeProps: {
label: "name",
children: "children"
},
typeMap: null,
selectRowIds: [],
allSelectRows: [],
isRefresh: false,
}
},
mounted() {
this.pageSo();
},
methods: {
setSelectedRows() {
this.$nextTick(() => {
Object.keys(this.$refs).forEach(key => {
if (key.startsWith('tableRef_')) {
const tableRef = this.$refs[key];
if (tableRef[0]) {
tableRef[0].clearSelection(); // 清除所有选择
this.inItems.forEach(([key, value]) => {
const ids = this.allSelectRows.map(item => item.id)
value.forEach(item => {
if (ids.includes(item.id)) {
tableRef[0].toggleRowSelection(item, true);
}
});
});
}
}
});
});
},
getDictDatasToType(type) {
return this.getDictDatas(type)
},
getTypeById(id) {
return this.typeMap.get(id)
},
async listServer() {
if (!this.serverList || this.serverList.length === 0) {
const res = await getBaseTypeList({type: "02"})
this.serverList = this.handleTree(res.data, 'id', 'parentId', "children", "0")
this.typeMap = new Map()
this.extractNodesToMap(this.serverList, this.typeMap)
}
},
extractNodesToMap(nodes, map) {
nodes.forEach(node => {
map.set(node.id, node.name);
if (node.children && node.children.length > 0) {
this.extractNodesToMap(node.children, map);
}
});
},
handleNodeClick(data, scopeRow) {
scopeRow.wares.type = data.id;
this.save(scopeRow)
},
optionData(array, result = []) {
array.forEach(item => {
result.push({label: item.name, value: item.id})
if (item.children && item.children.length !== 0) {
this.optionData(item.children, result)
}
})
return JSON.parse(JSON.stringify(result))
},
searchByQuery() {
this.isRefresh = true
this.getSoiList().then(() => {
this.setSelectedRows()
})
},
resetByQuery() {
this.allSelectRows = []
this.inItemsQuery = null
this.searchByQuery()
},
// 分页
async pageSo() {
this.queryParams.soType = null
this.queryParams.purchaseType = null
if (this.soByType && this.goodsYes) {
this.queryParams.soType = "03"
this.queryParams.purchaseType = "02"
} else if (this.soByType && !this.goodsYes) {
this.queryParams.soType = "01"
this.queryParams.purchaseType = "01"
} else if (!this.soByType && !this.isBack) {
this.queryParams.soType = "02"
} else if (this.isBack) {
this.queryParams.soType = '04'
}
try {
this.loading = true
const res = await getRepairSoPage(this.queryParams)
this.list = res.data.records
this.total = res.data.total
} finally {
this.loading = false
}
},
// 搜索按钮
handleQuery() {
this.queryParams.pageNo = 1
this.pageSo()
},
// 搜索重置
resetQuery() {
this.resetForm('queryForm')
this.queryParams.supplier = null
this.queryParams.corp = null
this.queryParams.user = null
this.handleQuery()
},
// 员工选择组件的回调
getStaff(data) {
this.queryParams.userId = data.id
this.queryParams.userName = data.name
},
// 门店选择
getCompany(data) {
console.log(data)
},
// 作废
handleVoidSo(row) {
this.$prompt('作废备注', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
}).then(({value}) => {
this.formData.id = row.id
this.formData.remark = value
this.doVoidSo()
}).catch(() => {
})
},
async doVoidSo() {
try {
await voidSo(this.formData)
this.$modal.msgSuccess("作废成功")
await this.pageSo()
} catch {
}
},
// 查看单据
async handleShow(row) {
const res = await getRepairSoById(row.id)
await this.$refs.soShow.open(res.data)
},
// 入库操作
async handleInWares(row) {
this.allSelectRows = []
this.inItemsQuery = null
await this.listServer()
this.soId = row.id
this.inWaresFormData = {
id: null,
soiList: []
}
this.inWaresFormData['id'] = row.id
await this.getSoiList()
},
async getSoiList() {
try {
this.dialogVisible = true
this.inLoading = true
const res = await getMapBySoIdAndQuery(this.soId, this.inItemsQuery)
this.inItems = Object.entries(res.data)
this.inItems = this.inItems.map(([key, value]) => {
return [key, value.filter(item => (!item.inCount && item.inCount !== item.goodsCount))]
})
this.inItems = this.inItems.filter(([key, value]) => value.length > 0)
this.inItems.forEach(([key, value]) => {
value.forEach(item => {
item.goodsCount = item.goodsCount - (item.inCount ? item.inCount : 0)
item.inCount = item.goodsCount
})
})
} finally {
this.inLoading = false
}
},
selectRow(row) {
this.selectRows = row
this.selectRowIds = row.map(item => item.id)
if (row && row.length > 0) {
// 添加新的选择到 allSelectRows
this.allSelectRows = [...this.allSelectRows, ...row.filter(item => !this.allSelectRows.some(allRow => allRow.id === item.id))];
} else {
// 用户取消选择了所有的行
this.allSelectRows = this.allSelectRows.filter(item => !this.selectRowIds.includes(item.id));
}
// 更新自身的数据
// 点搜索不走下面逻辑
if (!this.isRefresh) {
// 如果本页没有选中数据,那就把属于本页的数据全部删掉
// tableRef可能有多个全部取出来判断
const allRef = this.$refs
const newRef = Object.keys(allRef).filter(item => item.startsWith('tableRef_'))
newRef.forEach(tempRef => {
if (this.$refs[tempRef][0]) {
const ids = this.$refs[tempRef][0].data.map(item => item.id);
if (!row || row.length === 0) {
this.allSelectRows = this.allSelectRows.filter(item => !ids.includes(item.id))
} else {
// 把属于本页但是之前选中了本次没有选中的删掉
const rowIds = row.map(item => item.id)
const exIds = ids.filter(id => !rowIds.includes(id))
this.allSelectRows = this.allSelectRows.filter(item => !exIds.includes(item.id))
}
}
})
}
this.isRefresh = false
// 可能重复,去重
this.allSelectRows = this.allSelectRows.reduce((acc, item) => {
const flag = acc.find(i => i.id === item.id)
if (!flag) {
return acc.concat([item])
} else {
return acc
}
}, [])
},
async doInWares() {
try {
this.inWaresFormData.soiList = this.allSelectRows
this.inWaresFormData.waresList = this.allSelectRows.map(item => {
if (item.wares.ware){
item.wares.warehouse = item.wares.ware.id
}
return item.wares
})
this.inWaresFormData.soNo = createUniqueCodeByHead("RK")
this.inLoading = true
await inWare(this.inWaresFormData)
this.dialogVisible = false
this.$modal.msgSuccess("入库成功")
await this.pageSo()
} catch {
}
},
/** 鼠标移入cell */
handleCellEnter(row, column, cell, event) {
const property = column.property
if (row.id && this.editProp.includes(property)) {
cell.querySelector('.item__txt').classList.add('item__txt--hover')
}
},
/** 鼠标移出cell */
handleCellLeave(row, column, cell, event) {
const property = column.property
if (row.id && this.editProp.includes(property)) {
cell.querySelector('.item__txt').classList.remove('item__txt--hover')
}
},
/** 点击cell */
handleCellClick(row, column, cell, event) {
const property = column.property
if (this.editProp.includes(property)) {
if (!row.id || property !== 'goods') {
// 保存cell
this.saveCellClick(row, cell)
cell.querySelector('.item__txt').style.display = 'none'
cell.querySelector('.item__input').style.display = 'inline'
cell.querySelector('input').focus()
}
}
},
/** 取消编辑状态 */
cancelEditable(cell) {
cell.querySelector('.item__txt').style.display = 'inline'
cell.querySelector('.item__input').style.display = 'none'
},
/** 保存进入编辑的cell */
saveCellClick(row, cell) {
const id = row.id
if (this.clickCellMap[id] !== undefined) {
if (!this.clickCellMap[id].includes(cell)) {
this.clickCellMap[id].push(cell)
}
} else {
this.clickCellMap[id] = [cell]
}
},
/** 保存数据 */
save(row) {
const id = row.id
// 取消本行所有cell的编辑状态
this.clickCellMap[id].forEach(cell => {
this.cancelEditable(cell)
})
this.clickCellMap[id] = []
// this.tableKey++
// this.selectRows = []
},
}
}
</script>
<style scoped lang="scss">
.item {
.item__input {
display: none;
width: 100px;
/* 调整elementUI中样式 如果不需要调整请忽略 */
.el-input__inner {
height: 24px !important;
}
/* 调整elementUI中样式 如果不需要调整请忽略 */
.el-input__suffix {
i {
font-size: 12px !important;
line-height: 26px !important;
}
}
}
.item__txt {
box-sizing: border-box;
border: 1px solid transparent;
width: 100px;
line-height: 24px;
padding: 0 8px;
}
.item__txt--hover {
border: 1px solid #dddddd;
border-radius: 4px;
cursor: text;
}
}
</style>