This commit is contained in:
gtz
2022-11-07 08:45:49 +08:00
commit 4d1231adc2
1222 changed files with 194552 additions and 0 deletions

View File

@@ -0,0 +1,298 @@
<!--
* @Author: zwq
* @Date: 2020-12-29 15:41:11
* @LastEditors: lb
* @LastEditTime: 2022-03-18 11:00:00
* @Description:
-->
<template>
<div class="app-container">
<head-form :form-config="headFormConfig" @headBtnClick="btnClick" />
<base-table
:top-btn-config="topBtnConfig"
:page="listQuery.current"
:limit="listQuery.size"
:table-config="tableProps"
:table-data="areaList"
@emitFun="handleTableEvents"
@clickTopBtn="clickTopBtn"
>
<method-btn
slot="handleBtn"
:width="calculateWidth"
:method-list="tableBtn"
@clickBtn="handleClick"
/>
</base-table>
<pagination
v-show="total > 0"
:total="total"
:page.sync="listQuery.current"
:limit.sync="listQuery.size"
@pagination="getList()"
/>
<area-add-dialog
v-if="addOrUpdateVisible"
ref="addOrUpdate"
:cache-id="listQuery.cacheId"
@refreshDataList="getList"
@handleClosed="handleClosed"
/>
</div>
</template>
<script>
import i18n from '@/lang'
import { list, del, toggleEnable, getCacheList } from '@/api/basicData/Cache/area'
import HeadForm from '@/components/basicData/HeadForm'
import BaseTable from '@/components/BaseTable'
import Pagination from '@/components/Pagination' // Secondary package based on el-pagination
import MethodBtn from '@/components/BaseTable/subcomponents/MethodBtn'
import viewDetailBtn from '@/components/BaseTable/subcomponents/CommonBtn.vue'
import statusSwitch from './components/statusBtn.vue'
import areaAddDialog from './components/cacheArea-add.vue'
import { timeFormatter } from '@/filters'
/**
* 表格表头配置项 TypeScript接口注释
* tableConfig<ConfigItem> = []
*
* Interface ConfigItem = {
* prop: string,
* label: string,
* width: string,
* align: string,
* subcomponent: function,
* filter: function
* }
*
*
*/
const topBtnConfig = [
{
type: 'add',
btnName: 'btn.add'
}
]
const tableBtn = [
{
type: 'edit',
btnName: 'btn.edit'
},
{
type: 'delete',
btnName: 'btn.delete'
}
]
const tableProps = [
{
prop: 'createTime',
label: i18n.t('module.basicData.factory.createTime'),
filter: timeFormatter
},
{
prop: 'name',
label: i18n.t('module.basicData.cache.AreaNameInTable')
},
{
prop: 'code',
label: i18n.t('module.basicData.cache.AreaCodeInTable')
},
{
prop: 'cacheName',
label: i18n.t('module.basicData.cache.AreaCache')
},
{
prop: 'enName',
label: i18n.t('module.basicData.cache.EnglishName')
},
{
prop: 'enabled',
label: i18n.t('module.basicData.cache.AreaStatus'),
subcomponent: statusSwitch
},
{
prop: 'stockDetails',
label: i18n.t('module.basicData.cache.StockDetails'),
subcomponent: viewDetailBtn,
buttonContent: '查看详情'
}
]
export default {
name: 'Area',
components: { Pagination, BaseTable, MethodBtn, HeadForm, areaAddDialog },
filters: {
statusFilter(status) {
const statusMap = {
published: 'success',
draft: 'info',
deleted: 'danger'
}
return statusMap[status]
}
},
data() {
return {
topBtnConfig,
addOrUpdateVisible: false,
tableBtn,
trueWidth: 200,
tableProps,
areaList: [],
cacheList: [],
total: 0,
listLoading: true,
listQuery: {
current: 1,
size: 20
},
headFormConfig: [
{
type: 'input',
label: i18n.t('module.basicData.cache.Keywords'),
placeholder: this.$t('module.basicData.cache.AreaName'),
param: 'keyName'
},
{
type: 'button',
btnName: 'btn.search',
name: 'search',
color: 'primary'
}
],
headFormValue: {}
}
},
computed: {
calculateWidth() {
return this.tableBtn.length * 40 // 操作列的每个按钮宽度40
}
},
created() {
const params = {
current: 1,
size: 500
}
getCacheList(params).then(response => {
if (response.data.records) {
this.cacheList = response.data.records
this.getList()
}
})
},
methods: {
showStocksDialog(vArea) {
// 查看库位详情的功能在此处和编辑是一样的
this.addNew(vArea.id, true)
},
handleTableEvents({ action, data }) {
if (action === 'toggleEnabled') this.updateStatus(data)
else if (action === 'view-detail-action') this.showStocksDialog(data)
// 其他可能等用到再添加
},
updateStatus(vArea) {
// vArea 并非完整的 area 对象,而是接口需要的对象
toggleEnable(vArea).then(response => {
this.$message({
message: this.$t('module.basicData.visual.success'),
type: 'success',
duration: 1500,
onClose: () => {
this.getList()
}
})
})
},
handleClick(raw) {
if (raw.type === 'delete') {
this.$confirm(
`${this.$t('module.basicData.visual.TipsBefore')}[${raw.data.name}]?`,
this.$t('module.basicData.visual.Tips'),
{
confirmButtonText: this.$t('module.basicData.visual.confirmButtonText'),
cancelButtonText: this.$t('module.basicData.visual.cancelButtonText'),
type: 'warning'
}
)
.then(() => {
del(raw.data.id).then(response => {
this.$message({
message: this.$t('module.basicData.visual.success'),
type: 'success',
duration: 1500,
onClose: () => {
this.getList()
}
})
})
})
.catch(() => {})
} else if (raw.type === 'edit') {
this.addNew(raw.data.id)
} else {
this.addNew(raw.data.id, true)
}
},
getList() {
this.listLoading = true
this.listQuery.name = this.headFormValue.keyName
list(this.listQuery).then(response => {
if (response.data.records) {
this.areaList = response.data.records
this.areaList.forEach(item => {
const name = this.cacheList.find(citem => {
if (citem.id === item.cacheId) return citem
})
if (name) {
item.cacheName = name.name
}
})
} else {
this.areaList.splice(0, this.areaList.length)
}
this.total = response.data.total
this.listLoading = false
})
},
// 新增 / 修改
addNew(id, readonly) {
this.addOrUpdateVisible = true
this.$nextTick(() => {
this.$refs.addOrUpdate.init(id, 'area', readonly)
})
},
// 关闭弹窗
handleClosed() {
this.addOrUpdateVisible = false
},
btnClick(val) {
this.headFormValue = val
// 如果点击的是搜索栏的其他按钮在这里继续写判断
if (this.headFormValue.btnName === 'search') {
this.getList()
}
},
clickTopBtn(val) {
if (val === 'add') {
this.addNew() // 新增
}
}
}
}
</script>
<style scoped>
.edit-input {
padding-right: 100px;
}
.cancel-btn {
position: absolute;
right: 15px;
top: 10px;
}
</style>

View File

@@ -0,0 +1,319 @@
<!--
* @Author: zwq
* @Date: 2020-12-29 15:41:11
* @LastEditors: gtz
* @LastEditTime: 2022-07-25 10:29:31
* @Description:
-->
<template>
<div class="app-container">
<head-form :form-config="headFormConfig" @headBtnClick="btnClick" />
<base-table
:top-btn-config="topBtnConfig"
:page="listQuery.current"
:limit="listQuery.size"
:table-config="tableProps"
:table-data="cacheList"
:is-loading="listLoading"
@emitFun="handleTableEvents"
@clickTopBtn="clickTopBtn"
>
<method-btn
slot="handleBtn"
:width="calculateWidth"
:method-list="tableBtn"
@clickBtn="handleClick"
/>
</base-table>
<pagination
v-show="total > 0"
:total="total"
:page.sync="listQuery.current"
:limit.sync="listQuery.size"
@pagination="getList()"
/>
<!-- 新增|编辑 缓存区 -->
<cache-edit-dialog
v-if="showEditDialog"
ref="edit-dialog"
@refreshDataList="getList"
@handleClosed="handleClosed"
/>
<!-- 库位详情 -->
<stock-detail-dialog
v-if="addOrUpdateVisible"
ref="addOrUpdate"
:cache-id="listQuery.cacheId"
@refreshDataList="getList"
@handleClosed="handleClosed"
/>
</div>
</template>
<script>
import i18n from '@/lang'
import { list, del, toggleEnabled } from '@/api/basicData/Cache/cache'
import HeadForm from '@/components/basicData/HeadForm'
import BaseTable from '@/components/BaseTable'
import Pagination from '@/components/Pagination' // Secondary package based on el-pagination
import MethodBtn from '@/components/BaseTable/subcomponents/MethodBtn'
import { timeFormatter } from '@/filters'
import statusSwitch from './components/statusBtn.vue'
import viewDetailBtn from '@/components/BaseTable/subcomponents/CommonBtn.vue'
import cacheEditDialog from './components/cache-edit.vue'
import stockDetailDialog from './components/cacheArea-add.vue'
/**
* 表格表头配置项 TypeScript接口注释
* tableConfig<ConfigItem> = []
*
* Interface ConfigItem = {
* prop: string,
* label: string,
* width: string,
* align: string,
* subcomponent: function,
* filter: function
* }
*
*
*/
const topBtnConfig = [
{
type: 'add',
btnName: 'btn.add'
}
]
const tableBtn = [
{
type: 'edit',
btnName: 'btn.edit'
},
{
type: 'delete',
btnName: 'btn.delete'
}
]
const tableProps = [
{
prop: 'createTime',
label: i18n.t('module.basicData.factory.createTime'),
filter: timeFormatter
},
{
prop: 'name',
label: i18n.t('module.basicData.cache.CacheName')
},
{
prop: 'code',
label: i18n.t('module.basicData.cache.CacheCode')
},
{
prop: 'enName',
label: i18n.t('module.basicData.visual.EnglishName')
},
{
prop: 'enabled',
label: i18n.t('module.basicData.cache.AreaStatus'),
subcomponent: statusSwitch
},
{
prop: 'stockDetails',
label: i18n.t('module.basicData.cache.StockDetails'),
subcomponent: viewDetailBtn,
buttonContent: '查看详情',
detailType: 'cache'
}
]
export default {
name: 'Cache',
components: {
cacheEditDialog,
Pagination,
BaseTable,
MethodBtn,
HeadForm,
stockDetailDialog
},
filters: {
statusFilter(status) {
const statusMap = {
published: 'success',
draft: 'info',
deleted: 'danger'
}
return statusMap[status]
}
},
data() {
return {
showEditDialog: false,
topBtnConfig,
tableBtn,
trueWidth: 240,
tableProps,
cacheList: [],
total: 0,
listLoading: true,
listQuery: {
current: 1,
size: 20
},
addOrUpdateVisible: false,
headFormConfig: [
{
type: 'input',
label: i18n.t('module.basicData.visual.keyword'),
placeholder:
this.$t('module.basicData.cache.CacheName') +
this.$t('module.basicData.visual.Or') +
this.$t('module.basicData.cache.CacheCode'),
param: 'keyName',
width: 300
},
{
type: 'button',
btnName: 'btn.search',
name: 'search',
color: 'primary'
}
],
headFormValue: {}
}
},
computed: {
calculateWidth() {
return this.tableBtn.length * 40 // 操作列的每个按钮宽度40
}
},
created() {
this.getList()
},
methods: {
handleTableEvents({ action, data }) {
if (action === 'toggleEnabled') this.updateStatus(data)
else if (action === 'view-detail-action') this.viewStockDetails(data)
},
// 查看库位详情
viewStockDetails(vCache) {
this.addOrUpdateVisible = true
this.$nextTick(() => {
this.$refs.addOrUpdate.init(vCache.id, 'cache', true) // true 代表 readonly
})
},
// 切换启停状态
updateStatus(vCache) {
// vCache: nota a full cache obj, but the necessary part: { id, enabled }
toggleEnabled(vCache).then(response => {
this.$message({
message: this.$t('module.basicData.visual.success'),
type: 'success',
duration: 1500,
onClose: () => {
this.getList()
}
})
})
},
handleClick(raw) {
if (raw.type === 'delete') {
this.$confirm(
`${this.$t('module.basicData.visual.TipsBefore')}[${raw.data.name}]?`,
this.$t('module.basicData.visual.Tips'),
{
confirmButtonText: this.$t('module.basicData.visual.confirmButtonText'),
cancelButtonText: this.$t('module.basicData.visual.cancelButtonText'),
type: 'warning'
}
)
.then(() => {
del(raw.data.id).then(response => {
this.$message({
message: this.$t('module.basicData.visual.success'),
type: 'success',
duration: 1500,
onClose: () => {
this.getList()
}
})
})
})
.catch(() => {})
} else if (raw.type === 'edit') {
this.addNew(raw.data.id) // 传入 cacheId
} else {
this.addNew()
}
},
getList() {
this.listLoading = true
this.listQuery.name = this.headFormValue.keyName
this.listQuery.code = this.headFormValue.keyName
// 先清空list
this.cacheList.splice(0, this.cacheList.length)
// 再填满list, 可以实现在关闭编辑弹窗之后能同步更新table里的状态
list(this.listQuery).then(response => {
if (response.data.records) {
this.cacheList = response.data.records
} else {
this.cacheList.splice(0, this.cacheList.length)
}
this.total = response.data.total
this.listLoading = false
})
},
addNew(cacheId) {
this.showEditDialog = true
this.$nextTick(() => {
this.$refs['edit-dialog'].init(cacheId)
})
},
// 新增 / 修改
// addNew(id, isdetail) {
// this.$router.push({
// name: 'cacheAdd',
// query: {
// id: id,
// isdetail: isdetail
// }
// })
// },
handleClosed() {},
btnClick(val) {
this.headFormValue = val
// 如果点击的是搜索栏的其他按钮在这里继续写判断
if (this.headFormValue.btnName === 'search') {
this.getList()
}
},
clickTopBtn(val) {
if (val === 'add') {
this.addNew(null) // 新增
}
}
}
}
</script>
<style scoped>
.edit-input {
padding-right: 100px;
}
.cancel-btn {
position: absolute;
right: 15px;
top: 10px;
}
</style>

View File

@@ -0,0 +1,36 @@
<!--
* @Date: 2021-01-07 20:09:37
* @LastEditors: zwq
* @LastEditTime: 2021-07-21 14:18:59
* @FilePath: \basic-admin\src\components\BaseTable\subcomponents\CheckDetail.vue
* @Description:
-->
<template>
<span>
<el-button type="text" size="small" @click="emitClick">{{ $t('module.basicData.storageBox.PositionDetail') }}</el-button>
</span>
</template>
<script>
export default {
props: {
injectData: {
type: Object,
default: () => ({})
}
},
methods: {
emitClick() {
this.$router.push({
name: 'PositionDetailInfo',
query: {
id: this.injectData.id,
name: this.injectData.name,
code: this.injectData.code,
quantity: this.injectData.quantity
}
})
}
}
}
</script>

View File

@@ -0,0 +1,84 @@
<!--
* @Author: zwq
* @Date: 2020-12-29 16:37:56
* @LastEditors: zwq
* @LastEditTime: 2021-07-21 14:39:23
* @Description:
-->
<template>
<el-dialog
:title="!dataForm.id ? 'btn.add' : 'btn.edit' | i18nFilter"
:visible.sync="visible"
>
<el-form ref="dataForm" :model="dataForm" :rules="dataRule" label-width="100px" @keyup.enter.native="dataFormSubmit()">
<el-form-item :label="$t('module.basicData.storageBox.PositionCode')" prop="code">
<el-input v-model="dataForm.code" :placeholder="$i18nForm(['placeholder.input', $t('module.basicData.storageBox.PositionCode')])" clearable />
</el-form-item>
<el-form-item :label="$t('module.basicData.storageBox.PositionCodeAlias')" prop="aliasName">
<el-input v-model="dataForm.aliasName" :placeholder="$i18nForm(['placeholder.input', $t('module.basicData.storageBox.PositionCodeAlias')])" clearable />
</el-form-item>
<el-form-item :label="$t('module.basicData.storageBox.PositionNo')" prop="serial">
<el-input v-model="dataForm.serial" :placeholder="$i18nForm(['placeholder.input', $t('module.basicData.storageBox.PositionNo')])" clearable />
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="visible = false">{{ 'btn.cancel' | i18nFilter }}</el-button>
<el-button type="primary" @click="dataFormSubmit()">{{ 'btn.confirm' | i18nFilter }}</el-button>
</span>
</el-dialog>
</template>
<script>
import { PositionDetailInfoAdd } from '@/api/basicData/Cache/storageBox'
export default {
data() {
return {
visible: false,
dataForm: {
storageTankId: 0,
code: '',
aliasName: '',
serial: ''
},
dataRule: {
code: [
{
required: true,
message: this.$i18nForm(['placeholder.input', this.$t('module.basicData.storageBox.PositionCode')]),
trigger: 'blur' }
]
}
}
},
methods: {
init(id, code) {
this.dataForm.storageTankId = id || ''
this.visible = true
this.$nextTick(() => {
this.$refs['dataForm'].resetFields()
this.dataForm.code = code
})
},
// 表单提交
dataFormSubmit() {
this.$refs['dataForm'].validate((valid) => {
if (valid) {
const data = this.dataForm
PositionDetailInfoAdd(data).then(res => {
this.$message({
message: this.$t('module.basicData.visual.success'),
type: 'success',
duration: 1500,
onClose: () => {
this.visible = false
this.$emit('refreshDataList')
}
})
})
}
})
}
}
}
</script>

View File

@@ -0,0 +1,112 @@
<!--
* @Author: zwq
* @Date: 2021-07-21 14:05:30
* @LastEditors: zwq
* @LastEditTime: 2021-07-21 14:41:24
* @Description:
-->
<template>
<div style="margin:50px">
<span>{{ $t('module.basicData.storageBox.code') }}:{{ injectData.code }}</span>
<span>{{ $t('module.basicData.storageBox.name') }}:{{ injectData.name }}</span>
<span>{{ $t('module.basicData.storageBox.StorageQuantity') }}:{{ injectData.quantity }}</span>
<span>
<el-button type="primary" @click="addNew()">{{ 'btn.add' | i18nFilter }}</el-button>
<el-button type="success" @click="goback()">{{ 'btn.back' | i18nFilter }}</el-button>
</span>
<base-table
:page="listQuery.current"
:limit="listQuery.size"
:table-config="tableProps"
:table-data="list"
:is-loading="listLoading"
/>
<pagination
v-show="total > 0"
:total="total"
:page.sync="listQuery.current"
:limit.sync="listQuery.size"
@pagination="getList()"
/>
<PositionDetailInfo-add
v-if="addOrUpdateVisible"
ref="addOrUpdate"
:cache-id="listQuery.cacheId"
@refreshDataList="getList"
/>
</div>
</template>
<script>
import i18n from '@/lang'
import BaseTable from '@/components/BaseTable'
import Pagination from '@/components/Pagination' // Secondary package based on el-pagination
import PositionDetailInfoAdd from './PositionDetailInfo-add'
import { PositionDetailInfoList } from '@/api/basicData/Cache/storageBox'
const tableProps = [
{
prop: 'serial',
label: i18n.t('module.basicData.storageBox.PositionNo')
},
{
prop: 'code',
label: i18n.t('module.basicData.storageBox.PositionCode')
},
{
prop: 'aliasName',
label: i18n.t('module.basicData.storageBox.PositionCodeAlias')
}
]
export default {
components: { Pagination, BaseTable, PositionDetailInfoAdd },
data() {
return {
injectData: {},
addOrUpdateVisible: false,
tableProps,
list: [],
total: 0,
listLoading: true,
listQuery: {
current: 1,
size: 10
}
}
},
created() {
this.injectData = this.$route.query
this.getList()
},
methods: {
getList() {
this.listLoading = true
PositionDetailInfoList(this.listQuery).then(response => {
if (response.data.records) {
this.list = response.data.records
} else {
this.list.splice(0, this.list.length)
}
this.total = response.data.total
this.listLoading = false
})
},
// 新增 / 修改
addNew() {
this.addOrUpdateVisible = true
this.$nextTick(() => {
this.$refs.addOrUpdate.init(this.injectData.id, this.injectData.code)
})
},
goback() {
this.$router.go(-1)
}
}
}
</script>
<style scoped>
span {
margin-left: 30px;
}
</style>

View File

@@ -0,0 +1,243 @@
<!--
* @Author: lb
* @Date: 2022-03-14 15:00:00
* @LastEditors: juzi
* @LastEditTime: 2022-04-19
-->
<template>
<el-dialog :visible.sync="visible" :title="!isEdit ? 'btn.add' : 'btn.edit' | i18nFilter" @closed="handleClosed">
<!-- <span slot="title">
<small-title>
{{ !isEdit ? 'btn.add' : 'btn.edit' | i18nFilter }}
</small-title>
</span> -->
<div>
<el-form
ref="cacheForm"
:model="cacheForm"
:rules="cacheValidationRules"
label-width="100px"
@keyup.enter.native="submitCacheForm()"
>
<el-row :gutter="20">
<!-- 缓存区编码 -->
<el-col :span="12">
<el-form-item :label="$t('module.basicData.cache.CacheCode')" prop="code">
<el-input
v-model="cacheForm.code"
:placeholder="$i18nForm(['placeholder.input', $t('module.basicData.cache.CacheCode')])"
clearable
/>
</el-form-item>
</el-col>
<!-- 缓存区名称 -->
<el-col :span="12">
<el-form-item :label="$t('module.basicData.cache.CacheName')" prop="name">
<el-input
v-model="cacheForm.name"
:placeholder="$i18nForm(['placeholder.input', $t('module.basicData.cache.CacheName')])"
clearable
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<!-- 英文名 -->
<el-col :span="12">
<el-form-item :label="$t('module.basicData.cache.EnglishName')" prop="enName">
<el-input
v-model="cacheForm.enName"
:placeholder="$i18nForm(['placeholder.input', $t('module.basicData.cache.EnglishName')])"
clearable
/>
</el-form-item>
</el-col>
<!-- 缩写 -->
<el-col :span="12">
<el-form-item :label="$t('module.basicData.cache.abbr')" prop="abbr">
<el-input
v-model="cacheForm.abbr"
:placeholder="$i18nForm(['placeholder.input', $t('module.basicData.cache.abbr')])"
clearable
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<!-- 规格描述 -->
<el-col :span="12">
<el-form-item :label="$t('module.basicData.cache.Specs')" prop="description">
<el-input
v-model="cacheForm.description"
:placeholder="$i18nForm(['placeholder.input', $t('module.basicData.cache.Specs')])"
clearable
/>
</el-form-item>
</el-col>
<!-- 库位数 -->
<el-col :span="12">
<el-form-item :label="$t('module.basicData.cache.StockNumber')" prop="stockNumber">
<el-input-number
v-model="cacheForm.stockNumber"
type="number"
:min="0"
:step="1"
:placeholder="$i18nForm(['placeholder.input', $t('module.basicData.cache.StockNumber')])"
clearable
style="width: 100%;"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<!-- 当前状态 -->
<el-col>
<el-form-item :label="$t('module.basicData.cache.CurrentState')" prop="enabled">
<el-switch v-model="currentStatus" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<!-- 备注 -->
<el-col>
<el-form-item :label="$t('module.basicData.cache.Notes')" prop="remark">
<el-input
v-model="cacheForm.remark"
type="textarea"
:rows="2"
:placeholder="$i18nForm(['placeholder.input', $t('module.basicData.cache.Notes')])"
clearable
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="visible = false">{{ 'btn.cancel' | i18nFilter }}</el-button>
<el-button type="primary" @click="submitCacheForm">{{ 'btn.confirm' | i18nFilter }}</el-button>
</span>
</el-dialog>
</template>
<script>
import { getCode, detail, update, add } from '@/api/basicData/Cache/cache'
// import SmallTitle from '@/components/BaseDrawer/components/SmallTitle.vue'
export default {
// components: { SmallTitle },
props: {},
data() {
return {
isEdit: false, // false means isCreate
visible: false,
cacheForm: {
id: null,
code: '',
name: '',
enName: '',
abbr: '',
description: '',
stockNumber: 0,
remark: '',
enabled: 0
},
cacheValidationRules: {
name: [
{
required: true,
message: this.$i18nForm(['placeholder.input', this.$t('module.basicData.cache.CacheName')]),
trigger: 'blur'
}
],
code: [
{
required: true,
message: this.$i18nForm(['placeholder.input', this.$t('module.basicData.cache.CacheCode')]),
trigger: 'blur'
}
]
}
}
},
computed: {
currentStatus: {
get() {
return !!this.cacheForm.enabled
},
set(val) {
this.cacheForm.enabled = val ? 1 : 0
}
}
},
created() {
this.initCacheForm()
},
methods: {
// initialize this.cacheForm
initCacheForm() {
this.cacheForm.id = null
this.cacheForm.code = ''
this.cacheForm.name = ''
this.cacheForm.enName = ''
this.cacheForm.abbr = ''
this.cacheForm.description = ''
this.cacheForm.stockNumber = 0
this.cacheForm.remark = ''
this.cacheForm.enabled = 1 // 初始化默认的可用状态为true
},
// init
init(cacheId) {
this.initCacheForm()
// 显示对话框
this.visible = true
this.$nextTick(() => {
if (cacheId) {
this.isEdit = true
// 如果是编辑
this.cacheForm.id = cacheId
detail(this.cacheForm.id).then(response => {
this.cacheForm = response.data
})
} else {
this.isEdit = false
// 新增
getCode().then(response => {
this.cacheForm.code = response.data
})
}
})
},
submitCacheForm() {
this.$refs['cacheForm'].validate(valid => {
console.log(valid)
if (valid) {
const ajaxAction = this.isEdit ? update : add
ajaxAction(this.cacheForm).then(response => {
this.$message({
message: this.$t('module.basicData.visual.success'),
type: 'success',
duration: 1500,
onClose: () => {
this.visible = false
this.$emit('refreshDataList')
}
})
})
}
})
},
// 弹窗关闭
handleClosed() {
this.$emit('handleClosed')
}
}
}
</script>

View File

@@ -0,0 +1,772 @@
<!--
* @Author: zwq
* @Date: 2020-12-29 16:37:56
* @LastEditors: gtz
* @LastEditTime: 2022-07-25 10:29:42
* @Description:
-->
<template>
<!-- <el-dialog :visible.sync="visible" @closed="handleClosed" class="custom-dialog"> -->
<el-drawer :visible.sync="visible" :show-close="false" :wrapper-closable="false" class="drawer" :class="{ 'drawer-wider': showStocks }">
<span slot="title">
<small-title>
{{ readonly ? 'btn.detail' : !dataForm.id ? 'btn.add' : 'btn.edit' | i18nFilter }}
</small-title>
</span>
<div class="content">
<div class="visual-part">
<el-form
ref="dataForm"
:model="dataForm"
:rules="dataRule"
label-position="top"
@keyup.enter.native="dataFormSubmit()"
>
<el-row :gutter="20">
<!-- 缓存区/区域名 -->
<el-col :span="!showStocks ? 24 : 8">
<el-form-item
:label="isFromAreaPage ? $t('module.basicData.cache.AreaName') : $t('module.basicData.cache.CacheName')"
prop="name"
>
<el-input
v-model="dataForm.name"
:placeholder="
isFromAreaPage
? $i18nForm(['placeholder.input', $t('module.basicData.cache.AreaName')])
: $i18nForm(['placeholder.input', $t('module.basicData.cache.CacheName')])
"
:disabled="readonly"
clearable
/>
</el-form-item>
</el-col>
<!-- 区域编码 -->
<el-col :span="!showStocks ? 24 : 8">
<el-form-item v-if="isFromAreaPage" :label="$t('module.basicData.cache.AreaCode')" prop="code">
<el-input
v-model="dataForm.code"
:placeholder="
isFromAreaPage
? $i18nForm(['placeholder.input', $t('module.basicData.cache.AreaCode')])
: $i18nForm(['placeholder.input', $t('module.basicData.cache.CacheCode')])
"
:disabled="readonly"
clearable
/>
</el-form-item>
</el-col>
<!-- 缓存区id -->
<el-col :span="!showStocks ? 24 : 8">
<el-form-item v-if="isFromAreaPage" :label="$t('module.basicData.cache.CacheName')" prop="cacheId">
<el-select
v-model="dataForm.cacheId"
filterable
:placeholder="$i18nForm(['placeholder.input', $t('module.basicData.cache.CacheName')])"
clearable
:disabled="readonly"
>
<el-option v-for="item in cacheArr" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template v-if="showStocks">
<!-- 分隔标题: 基础资料/库位详情 -->
<small-title :size="'sm'">
{{ 'routerTitle.basicData.ports.locationDetails' | i18nFilter }}
</small-title>
<el-row v-if="isFromAreaPage && !readonly">
<!-- 不是从'缓存区页面'弹出的此页面就允许展示'新建库位'按钮 -->
<div v-if="displayCreateStockButton">
<button
style="cursor: pointer; margin-top: 8px; color: #0b58ff; border:none; outline:none; background: none;"
@click.prevent="displayCreateStockForm"
>
{{ 'btn.add' | i18nFilter }}{{ 'routerTitle.basicData.ports.locationAdd' | i18nFilter }}
</button>
</div>
<div v-else>
<el-form
ref="stockForm"
style="padding: 24px 0; text-align: center"
:model="stockForm"
label-width="80px"
:rules="stockFormValidationRules"
label-position="left"
>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item :label="$t('module.basicData.cache.AreaName')" prop="areaId">
<!-- <el-input v-model="stockForm.areaId" disabled clearable /> -->
<el-input v-model="dataForm.name" disabled clearable />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="$t('module.basicData.cache.LocationCode')" prop="code">
<el-input v-model="stockForm.code" clearable />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="$t('module.basicData.cache.LocationName')" prop="name">
<el-input v-model="stockForm.name" clearable />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item :label="$t('module.basicData.cache.LocationAlias')" prop="anotherName">
<el-input v-model="stockForm.anotherName" clearable />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="$t('module.basicData.cache.EnglishName')" prop="enName">
<el-input v-model="stockForm.enName" clearable />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="$t('module.basicData.cache.Notes')" prop="remark">
<el-input v-model="stockForm.remark" clearable />
</el-form-item>
</el-col>
</el-row>
<div style="display: flex; justify-content: flex-end;">
<el-button @click="displayCreateStockButton = true">
{{ 'btn.cancel' | i18nFilter }}
</el-button>
<el-button type="primary" @click="stockCreateOrEditController">
{{ 'btn.confirm' | i18nFilter }}
</el-button>
</div>
</el-form>
</div>
</el-row>
<template v-if="hasStocks">
<el-row>
<base-table
:page="listQuery.current"
:limit="listQuery.size"
:table-data="stocks"
:table-config="tableProps"
@emitFun="toggleStockEnabled"
>
<template v-if="!readonly">
<method-btn
slot="handleBtn"
:width="trueWidth"
:method-list="tableBtn"
@clickBtn="stockClickHandler"
/>
</template>
</base-table>
<pagination
v-show="total > 0"
:total="total"
:page-sizes="[3, 5, 10, 20]"
:page.sync="listQuery.current"
:limit.sync="listQuery.size"
@pagination="fetchStocks"
/>
</el-row>
</template>
<template v-else>
<div
style="color: #c0c0c0; display: inline-block; font-size: 32px; padding: 1em; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);"
>
暂无库位信息
</div>
</template>
</template>
</div>
<div style="position: absolute; bottom: 24px; right: 24px;">
<el-button @click="visible = false">{{ 'btn.cancel' | i18nFilter }}</el-button>
<el-button type="primary" @click="dataFormSubmit()">{{ 'btn.confirm' | i18nFilter }}</el-button>
</div>
</div>
<!-- </el-dialog> -->
</el-drawer>
</template>
<script>
import {
detail as areaDetail,
update as areaUpdate,
add as areaAdd,
getCode as areaCode,
getLocations as getLocationsOfArea
} from '@/api/basicData/Cache/area'
import {
list as cacheList,
detail as cacheDetail,
getCode as cacheCode,
getLocations as getLocationsOfCache
} from '@/api/basicData/Cache/cache'
import {
getCode as locationCode,
add as locationAdd,
toggleLocationStatus as locationToggleEnabled,
del as locationDelete,
update as locationUpdate
} from '@/api/basicData/Cache/location'
import Pagination from '@/components/Pagination'
import BaseTable from '@/components/BaseTable'
import i18n from '@/lang'
import { timeFormatter } from '@/filters'
import statusSwitch from './statusBtn.vue'
import MethodBtn from '@/components/BaseTable/subcomponents/MethodBtn'
import SmallTitle from '@/components/BaseDrawer/components/SmallTitle.vue'
const tableBtn = [
{
type: 'edit',
btnName: 'btn.edit'
},
{
type: 'delete',
btnName: 'btn.delete'
}
]
// 区域页面库位详情表格配置
const areaStockTableProps = [
{
prop: 'createTime',
label: i18n.t('module.basicData.factory.createTime'),
filter: timeFormatter,
width: 180
},
{
prop: 'name',
label: i18n.t('module.basicData.cache.LocationName')
},
{
prop: 'code',
label: i18n.t('module.basicData.cache.LocationCode'),
width: 180
},
{
prop: 'anotherName',
label: i18n.t('module.basicData.cache.LocationAlias')
},
{
prop: 'enName',
label: i18n.t('module.basicData.cache.EnglishName')
},
{
prop: 'enabled',
label: i18n.t('module.basicData.cache.AreaStatus'),
subcomponent: statusSwitch
// readonly: true, // 证实可行
}
]
// 缓存区页面库位详情表格配置
const cacheStockTableProps = [
{
prop: 'areaName',
label: i18n.t('module.basicData.cache.AreaName')
},
{
prop: 'name',
label: i18n.t('module.basicData.cache.LocationName')
},
{
prop: 'code',
label: i18n.t('module.basicData.cache.LocationCode')
},
{
prop: 'anotherName',
label: i18n.t('module.basicData.cache.LocationAlias')
},
{
prop: 'enName',
label: i18n.t('module.basicData.cache.EnglishName')
},
{
prop: 'enabled',
label: i18n.t('module.basicData.cache.AreaStatus'),
subcomponent: statusSwitch
}
]
export default {
components: {
BaseTable,
MethodBtn,
Pagination,
SmallTitle
},
props: {
cacheId: {
type: String,
default: () => {
return ''
}
}
},
data() {
return {
readonly: false, // 开启不可编辑状态
// 库位信息
stockEdit: false,
stockForm: {
areaId: '',
code: '',
name: '',
anotherName: '',
id: '',
enName: '',
remark: '',
cacheId: ''
},
displayCreateStockButton: true,
total: 0,
listQuery: {
current: 1, // 固定默认请求第1页
size: 3 // 固定默认请求3条数据
},
showStocks: false,
listLoading: true,
trueWidth: 200,
tableBtn,
stocks: [],
tableProps: null,
visible: false,
isFromAreaPage: false,
// 表单数据
dataForm: {
// 这是一个'区域'和'缓存区'复用的结构
id: 0, // 区域id | 缓存区id
cacheId: '', // 显式地保存缓存区id
name: '', // 区域/缓存区名称
code: '', // 区域/缓存区编码
areaNumber: '', // 缓存区里的区域数量
enabled: 1 // 区域启停状态默认为1
},
cacheArr: [],
// 表单验证
dataRule: {
name: [
{
required: true,
message: this.$i18nForm(['placeholder.input', this.$t('module.basicData.cache.AreaName')]),
trigger: 'blur'
}
],
code: [
{
required: true,
message: this.$i18nForm(['placeholder.input', this.$t('module.basicData.cache.AreaCode')]),
trigger: 'blur'
}
],
cacheId: [
{
required: true,
message: this.$i18nForm(['placeholder.input', this.$t('module.basicData.cache.CacheName')]),
trigger: 'change'
}
]
},
stockFormValidationRules: {
areaId: [
{
required: true,
message: this.$i18nForm(['placeholder.input', this.$t('module.basicData.cache.AreaId')]),
trigger: 'blur'
}
],
name: [
{
required: true,
message: this.$i18nForm(['placeholder.input', this.$t('module.basicData.cache.LocationName')]),
trigger: 'blur'
}
],
code: [
{
required: true,
message: this.$i18nForm(['placeholder.input', this.$t('module.basicData.cache.LocationCode')]),
trigger: 'blur'
}
]
}
}
},
computed: {
hasStocks() {
return this.stocks?.length > 0
}
},
methods: {
// 判断当前是库位的编辑,还是库位的新增
stockCreateOrEditController() {
if (this.stockEdit) {
// 编辑
this.submitEditStockForm()
} else {
// 新增
this.submitCreateStockForm()
}
},
// 库位的编辑操作
stockClickHandler(raw) {
if (raw.type === 'delete') {
this.$confirm(
`${this.$t('module.basicData.visual.TipsBefore')}[${raw.data.name}]?`,
this.$t('module.basicData.visual.Tips'),
{
confirmButtonText: this.$t('module.basicData.visual.confirmButtonText'),
cancelButtonText: this.$t('module.basicData.visual.cancelButtonText'),
type: 'warning'
}
)
.then(() => {
// 删除区域里的一个库位
locationDelete(raw.data.id).then(response => {
this.$message({
message: this.$t('module.basicData.visual.success'),
type: 'success',
duration: 1500,
onClose: () => {
this.fetchStocks()
}
})
})
})
.catch(() => {})
} else if (raw.type === 'edit') {
// 调取本页的库位编辑页面相关代码
this.displayEditStockForm(raw.data)
}
},
toggleStockEnabled({ data: vStock }) {
locationToggleEnabled(vStock).then(response => {
this.$message({
message: this.$t('module.basicData.visual.success'),
type: 'success',
duration: 1500,
onClose: () => {
this.fetchStocks()
}
})
})
},
submitEditStockForm() {
// 库位编辑 表单提交
this.$refs['stockForm'].validate(valid => {
if (valid) {
locationUpdate(this.stockForm).then(response => {
this.$message({
message: this.$t('module.basicData.visual.success'),
type: 'success',
duration: 1500,
onClose: () => {
this.displayCreateStockButton = true
this.fetchStocks()
}
})
})
}
})
},
submitCreateStockForm() {
// 库位新增 表单提交
this.$refs['stockForm'].validate(valid => {
if (valid) {
locationAdd(this.stockForm).then(response => {
this.$message({
message: this.$t('module.basicData.visual.success'),
type: 'success',
duration: 1500,
onClose: () => {
this.displayCreateStockButton = true
this.fetchStocks()
}
})
})
}
})
},
displayCreateStockForm() {
// 展示新增库位表单
this.initStockForm()
this.stockEdit = false
this.displayCreateStockButton = false
this.$nextTick(() => {
// 清空表单
this.$refs['stockForm'].resetFields()
// 请求并填充库位code
locationCode().then(response => {
this.stockForm.code = response.data
})
// 填充库位的区域ID | 缓存区ID
this.stockForm.areaId = this.dataForm.id || null
})
},
displayEditStockForm(stockData) {
// 点击编辑库位信息时触发
this.stockEdit = true
this.displayCreateStockButton = false
this.$nextTick(() => {
this.$refs['stockForm'].resetFields()
// 填充当前库位的相关数据
this.stockForm.id = stockData.id // 库位id
this.stockForm.code = stockData.code
this.stockForm.name = stockData.name
this.stockForm.anotherName = stockData.anotherName || ''
this.stockForm.remark = stockData.remark || ''
this.stockForm.enName = stockData.enName || ''
this.stockForm.areaId = this.dataForm.id || '' // 库位所属的区域id | 缓存区id
})
},
fetchStocks() {
if (this.isFromAreaPage) {
this.fetchStocksInArea()
} else {
this.fetchStocksInCache()
}
},
fetchStocksInCache() {
this.showStocks = true
// 获取缓存区库位列表(分页),供'库位详情'时调用
getLocationsOfCache({
cacheId: this.dataForm.id,
...this.listQuery
}).then(response => {
// 把响应数据放进表格
this.stocks = response.data.records || []
this.total = response.data.total
// if (this.total > 0) {
// this.showStocks = true
// }
})
},
fetchStocksInArea() {
this.showStocks = true
// 获取区域库位列表(分页),供'编辑'时调用
getLocationsOfArea({
areaId: this.dataForm.id,
...this.listQuery
}).then(response => {
// 把响应数据放进表格
this.stocks = response.data.records || []
this.total = response.data.total
// if (this.total > 0) {
// this.showStocks = true
// }
})
},
initStockForm() {
// 初始化库位表单
this.stockForm = {
areaId: null,
code: '',
name: '',
anotherName: '',
id: '',
enName: '',
remark: '',
cacheId: null
}
},
init(id, entry, readonly) {
// id: 区域的id | 缓存区的id
// entry: area | cache
this.dataForm.id = id || ''
this.stocks.splice(0)
this.showStocks = false
// 判断使用什么 tableProps:
if (entry === 'area') this.tableProps = areaStockTableProps
else if (entry === 'cache') this.tableProps = cacheStockTableProps
// readonly 代表当前是可编辑状态还是只读状态,默认都是可编辑
this.readonly = !!readonly
// 如果是 readonly 模式,则需要修改 tableProps
if (readonly) {
this.tableProps.forEach((obj, index) => {
if (obj.prop === 'enabled') {
this.$set(obj, 'readonly', this.readonly)
}
})
} else {
// 如果不是 readonly需要显式的删除 tableProps 里 swtichBtn 子组件的 readonly 属性
// 因为 cacheArea-add.vue 这个组件在area页面被复用了2次不这么做的话一旦添加readonly
// 之后所有的复用都会携带readonly造成不希望的后果
this.tableProps.forEach((obj, index) => {
if (obj.prop === 'enabled' && Object.prototype.hasOwnProperty.call(obj, 'readonly')) {
this.$delete(obj, 'readonly')
}
})
}
// 此文件会被复用,所以需要做通用化处理
if (entry === 'area') {
// 如果是从区域界面进入此组件,则需要获取缓存区列表
// 因为要选择正在编辑的区域属于哪一个缓存区:
// 1.获取所有缓存区列表
this.cacheArr.splice(0, this.cacheArr.length)
const params = {
current: 1,
size: 500
}
cacheList(params).then(response => {
if (response.data.records) {
this.cacheArr = response.data.records
}
})
this.isFromAreaPage = true
} else if (entry === 'cache') {
this.isFromAreaPage = false
}
// 选择接口
const fetchDetail = this.isFromAreaPage ? areaDetail : cacheDetail
const fetchCode = this.isFromAreaPage ? areaCode : cacheCode
// 显示弹窗
this.visible = true
this.$nextTick(() => {
this.$refs['dataForm'].resetFields()
if (this.dataForm.id) {
// 如果是编辑则通过id获取'区域|缓存区'的详情
fetchDetail(this.dataForm.id).then(res => {
this.dataForm = res.data
})
// 检查区域是否有库位,有则展示
this.fetchStocks()
} else {
// 缓存区新增不在这里面完成所以不需要fetchCode
// 为了保持代码风格的统一,写上也无妨,缓存区调用此组件时压根就不会走到此分支
// 如果是新增,就请求一个'区域编码'来填充表单
fetchCode().then(res => {
this.dataForm.code = res.data
})
// 新增时,不展示库位信息
this.showStocks = false
}
})
},
// 表单提交
dataFormSubmit() {
// 如果是从 area 页面来,就提交表单,否则直接关闭即可
if (this.isFromAreaPage && !this.readonly) {
this.$refs['dataForm'].validate(valid => {
if (valid) {
const data = this.dataForm
if (this.dataForm.id) {
areaUpdate(data).then(res => {
this.$message({
message: this.$t('module.basicData.visual.success'),
type: 'success',
duration: 1500,
onClose: () => {
this.visible = false
this.$emit('refreshDataList')
}
})
})
} else {
areaAdd(data).then(res => {
this.$message({
message: this.$t('module.basicData.visual.success'),
type: 'success',
duration: 1500,
onClose: () => {
this.visible = false
this.$emit('refreshDataList')
}
})
// 通过返回的区域id获取对应的库位列表
// this.dataForm.id = res.data.id
// this.fetchStocks()
// this.showStocks = true
})
}
}
})
} else {
this.visible = false
}
},
// 弹窗关闭
handleClosed() {
// this.$emit('handleClosed')
// if (this.dataForm.id) {
// 如果是编辑
this.$emit('refreshDataList')
// }
}
}
}
</script>
<style scoped>
.custom-dialog >>> .el-dialog__body {
padding: 30px 24px;
}
.drawer >>> .el-drawer {
transition: all .3s ease-out;
border-radius: 8px 0 0 8px;
}
.drawer >>> .el-form-item__label {
padding: 0;
}
.drawer >>> .el-drawer__header {
margin: 0;
padding: 32px 32px 24px;
border-bottom: 1px solid #dcdfe6;
margin-bottom: 30px;
}
.drawer >>> .content {
padding: 0 24px 30px;
display: flex;
flex-direction: column;
height: 100%;
}
.drawer >>> .visual-part {
flex: 1 auto;
max-height: 76vh;
overflow: hidden;
overflow-y: scroll;
padding-right: 10px; /* 调整滚动条样式 */
}
.drawer-wider >>> .el-drawer {
width: 60% !important;
}
</style>

View File

@@ -0,0 +1,189 @@
<!--
* @Author: zwq
* @Date: 2020-12-29 15:41:11
* @LastEditors: gtz
* @LastEditTime: 2022-07-25 10:29:46
* @Description:
-->
<template>
<div class="app-container">
<div style="margin:10px 50px">
<el-button type="success" @click="goback()">{{ 'btn.back' | i18nFilter }}</el-button>
<el-button type="primary" @click="addNew()">{{ 'btn.add' | i18nFilter }}</el-button>
</div>
<base-table
:page="listQuery.current"
:limit="listQuery.size"
:table-config="tableProps"
:table-data="list"
:is-loading="listLoading"
>
<method-btn slot="handleBtn" :width="trueWidth" :method-list="tableBtn" @clickBtn="handleClick" />
</base-table>
<locationAttr-add
v-if="addOrUpdateVisible"
ref="addOrUpdate"
:shelf-id="listQuery.shelfId"
@refreshDataList="getList"
/>
</div>
</template>
<script>
import i18n from '@/lang'
import { locationList, locationDelete } from '@/api/basicData/Cache/location'
import locationAttrAdd from './locationAttr-add.vue'
import BaseTable from '@/components/BaseTable'
import MethodBtn from '@/components/BaseTable/subcomponents/MethodBtn'
import { timeFormatter } from '@/filters'
/**
* 表格表头配置项 TypeScript接口注释
* tableConfig<ConfigItem> = []
*
* Interface ConfigItem = {
* prop: string,
* label: string,
* width: string,
* align: string,
* subcomponent: function,
* filter: function
* }
*
*
*/
const tableBtn = [
{
type: 'edit',
btnName: 'btn.edit'
},
{
type: 'delete',
btnName: 'btn.delete'
}
]
const tableProps = [
{
prop: 'createTime',
label: i18n.t('module.basicData.factory.createTime'),
filter: timeFormatter
},
{
prop: 'code',
label: i18n.t('module.basicData.cache.LocationCode')
},
{
prop: 'name',
label: i18n.t('module.basicData.cache.LocationName')
},
{
prop: 'anotherName',
label: i18n.t('module.basicData.cache.anotherName')
},
{
prop: 'place',
label: i18n.t('module.basicData.cache.place')
},
{
prop: 'remark',
label: i18n.t('module.basicData.visual.Remarks')
}
]
export default {
name: 'Location',
components: { BaseTable, MethodBtn, locationAttrAdd },
filters: {
statusFilter(status) {
const statusMap = {
published: 'success',
draft: 'info',
deleted: 'danger'
}
return statusMap[status]
}
},
data() {
return {
addOrUpdateVisible: false,
tableBtn,
trueWidth: 200,
tableProps,
list: [],
listLoading: true,
listQuery: {
current: 1,
size: 990,
shelfId: ''
}
}
},
created() {
this.listQuery.shelfId = this.$route.query.id
this.getList()
},
methods: {
handleClick(raw) {
if (raw.type === 'delete') {
this.$confirm(
`${this.$t('module.basicData.visual.TipsBefore')}[${raw.data.name}]?`,
this.$t('module.basicData.visual.Tips'),
{
confirmButtonText: this.$t('module.basicData.visual.confirmButtonText'),
cancelButtonText: this.$t('module.basicData.visual.cancelButtonText'),
type: 'warning'
}
)
.then(() => {
locationDelete(raw.data.id).then(response => {
this.$message({
message: this.$t('module.basicData.visual.success'),
type: 'success',
duration: 1500,
onClose: () => {
this.getList()
}
})
})
})
.catch(() => {})
} else {
this.addNew(raw.data.id)
}
},
getList(key) {
this.listLoading = true
this.listQuery.name = key
locationList(this.listQuery).then(response => {
if (response.data.records) {
this.list = response.data.records
} else {
this.list.splice(0, this.list.length)
}
this.listLoading = false
})
},
// 新增 / 修改
addNew(shelfId) {
this.addOrUpdateVisible = true
this.$nextTick(() => {
this.$refs.addOrUpdate.init(shelfId)
})
},
goback() {
this.$router.go(-1)
}
}
}
</script>
<style scoped>
.edit-input {
padding-right: 100px;
}
.cancel-btn {
position: absolute;
right: 15px;
top: 10px;
}
</style>

View File

@@ -0,0 +1,130 @@
<!--
* @Author: zwq
* @Date: 2020-12-29 16:37:56
* @LastEditors: lb
* @LastEditTime: 2022-03-17 16:36:00
* @Description:
-->
<template>
<el-dialog
:title="!dataForm.shelfId ? 'btn.add' : 'btn.edit' | i18nFilter"
:visible.sync="visible"
>
<el-form ref="dataForm" :model="dataForm" :rules="dataRule" label-width="100px" @keyup.enter.native="dataFormSubmit()">
<el-form-item :label="$t('module.basicData.cache.LocationName')" prop="name">
<el-input v-model="dataForm.name" :placeholder="$i18nForm(['placeholder.input', $t('module.basicData.cache.LocationName')])" clearable />
</el-form-item>
<el-form-item :label="$t('module.basicData.cache.LocationCode')" prop="code">
<el-input v-model="dataForm.code" :placeholder="$i18nForm(['placeholder.input', $t('module.basicData.cache.LocationCode')])" clearable />
</el-form-item>
<el-form-item :label="$t('module.basicData.cache.anotherName')" prop="anotherName">
<el-input v-model="dataForm.anotherName" :placeholder="$i18nForm(['placeholder.input', $t('module.basicData.cache.anotherName')])" clearable />
</el-form-item>
<el-form-item :label="$t('module.basicData.cache.place')" prop="place">
<el-input v-model="dataForm.place" :placeholder="$i18nForm(['placeholder.input', $t('module.basicData.cache.place')])" clearable />
</el-form-item>
<el-form-item :label="$t('module.basicData.cache.Notes')" prop="remark">
<el-input v-model="dataForm.remark" :placeholder="$i18nForm(['placeholder.input', $t('module.basicData.cache.Notes')])" clearable />
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="visible = false">{{ 'btn.cancel' | i18nFilter }}</el-button>
<el-button type="primary" @click="dataFormSubmit()">{{ 'btn.confirm' | i18nFilter }}</el-button>
</span>
</el-dialog>
</template>
<script>
import { locationDetail, locationUpdate, locationAdd, locationCode } from '@/api/basicData/Cache/location'
export default {
props: {
shelfId: {
type: String,
default: () => {
return ''
}
}
},
data() {
return {
visible: false,
dataForm: {
id: 0,
name: '',
code: '',
anotherName: '',
place: '',
remark: ''
},
dataRule: {
name: [
{ required: true, message: this.$i18nForm(['placeholder.input', this.$t('module.basicData.cache.LocationName')]), trigger: 'blur' }
],
code: [
{ required: true, message: this.$i18nForm(['placeholder.input', this.$t('module.basicData.cache.LocationCode')]), trigger: 'blur' }
]
}
}
},
methods: {
init(id) {
this.dataForm.id = id || ''
this.visible = true
this.$nextTick(() => {
this.$refs['dataForm'].resetFields()
if (this.dataForm.id) {
locationDetail(this.dataForm.id).then(res => {
this.dataForm = res.data
})
} else {
locationCode().then(res => {
this.dataForm.code = res.data
})
}
})
},
// 表单提交
dataFormSubmit() {
this.$refs['dataForm'].validate((valid) => {
if (valid) {
const data = {
'name': this.dataForm.name,
'code': this.dataForm.code,
'anotherName': this.dataForm.anotherName,
'place': this.dataForm.place,
'remark': this.dataForm.remark,
'shelfId': this.shelfId,
'id': this.dataForm.id
}
if (this.dataForm.id) {
locationUpdate(data).then(res => {
this.$message({
message: this.$t('module.basicData.visual.success'),
type: 'success',
duration: 1500,
onClose: () => {
this.visible = false
this.$emit('refreshDataList')
}
})
})
} else {
locationAdd(data).then(res => {
this.$message({
message: this.$t('module.basicData.visual.success'),
type: 'success',
duration: 1500,
onClose: () => {
this.visible = false
this.$emit('refreshDataList')
}
})
})
}
}
})
}
}
}
</script>

View File

@@ -0,0 +1,33 @@
<!--
* @Date: 2021-01-07 20:09:37
* @LastEditors: zwq
* @LastEditTime: 2021-03-06 13:12:47
* @FilePath: \basic-admin\src\components\BaseTable\subcomponents\CheckDetail.vue
* @Description:
-->
<template>
<span>
<el-button type="text" size="small" @click="emitClick">{{ $t('module.basicData.cache.ManageLocation') }}</el-button>
</span>
</template>
<script>
export default {
props: {
injectData: {
type: Object,
default: () => ({})
}
},
methods: {
emitClick() {
this.$router.push({
name: 'locationAdd',
query: {
id: this.injectData.id
}
})
}
}
}
</script>

View File

@@ -0,0 +1,182 @@
<!--
* @Author: zwq
* @Date: 2020-12-29 15:41:11
* @LastEditors: gtz
* @LastEditTime: 2022-07-25 10:29:49
* @Description:
-->
<template>
<div class="app-container">
<div style="margin:10px 50px">
<el-button type="success" @click="goback()">{{ 'btn.back' | i18nFilter }}</el-button>
<el-button type="primary" @click="addNew()">{{ 'btn.add' | i18nFilter }}</el-button>
</div>
<base-table
:page="listQuery.current"
:limit="listQuery.size"
:table-config="tableProps"
:table-data="shelfList"
:is-loading="listLoading"
>
<method-btn slot="handleBtn" :width="trueWidth" :method-list="tableBtn" @clickBtn="handleClick" />
</base-table>
<shelfAttr-add v-if="addOrUpdateVisible" ref="addOrUpdate" :area-id="listQuery.areaId" @refreshDataList="getList" />
</div>
</template>
<script>
import i18n from '@/lang'
import { list, del } from '@/api/basicData/Cache/shelf'
import shelfAttrAdd from './shelfAttr-add.vue'
import locationBtn from './locationBtn.vue'
import BaseTable from '@/components/BaseTable'
import MethodBtn from '@/components/BaseTable/subcomponents/MethodBtn'
import { timeFormatter } from '@/filters'
/**
* 表格表头配置项 TypeScript接口注释
* tableConfig<ConfigItem> = []
*
* Interface ConfigItem = {
* prop: string,
* label: string,
* width: string,
* align: string,
* subcomponent: function,
* filter: function
* }
*
*
*/
const tableBtn = [
{
type: 'edit',
btnName: 'btn.edit'
},
{
type: 'delete',
btnName: 'btn.delete'
}
]
const tableProps = [
{
prop: 'createTime',
label: i18n.t('module.basicData.cache.createTime'),
filter: timeFormatter
},
{
prop: 'code',
label: i18n.t('module.basicData.cache.ShelfCode')
},
{
prop: 'name',
label: i18n.t('module.basicData.cache.ShelfName')
},
{
prop: 'shelfNumber',
label: i18n.t('module.basicData.cache.StorageQuantity')
},
{
prop: 'location',
label: i18n.t('module.basicData.cache.Location'),
subcomponent: locationBtn
}
]
export default {
name: 'Shelf',
components: { BaseTable, MethodBtn, shelfAttrAdd },
filters: {
statusFilter(status) {
const statusMap = {
published: 'success',
draft: 'info',
deleted: 'danger'
}
return statusMap[status]
}
},
data() {
return {
addOrUpdateVisible: false,
tableBtn,
trueWidth: 200,
tableProps,
shelfList: [],
listLoading: true,
listQuery: {
current: 1,
size: 990,
areaId: ''
}
}
},
created() {
this.listQuery.areaId = this.$route.query.id
this.getList()
},
methods: {
handleClick(raw) {
if (raw.type === 'delete') {
this.$confirm(
`${this.$t('module.basicData.visual.TipsBefore')}[${raw.data.name}]?`,
this.$t('module.basicData.visual.Tips'),
{
confirmButtonText: this.$t('module.basicData.visual.confirmButtonText'),
cancelButtonText: this.$t('module.basicData.visual.cancelButtonText'),
type: 'warning'
}
)
.then(() => {
del(raw.data.id).then(response => {
this.$message({
message: this.$t('module.basicData.visual.success'),
type: 'success',
duration: 1500,
onClose: () => {
this.getList()
}
})
})
})
.catch(() => {})
} else {
this.addNew(raw.data.id)
}
},
getList(key) {
this.listLoading = true
this.listQuery.name = key
list(this.listQuery).then(response => {
if (response.data.records) {
this.shelfList = response.data.records
} else {
this.shelfList.splice(0, this.shelfList.length)
}
this.listLoading = false
})
},
// 新增 / 修改
addNew(id) {
this.addOrUpdateVisible = true
this.$nextTick(() => {
this.$refs.addOrUpdate.init(id)
})
},
goback() {
this.$router.go(-1)
}
}
}
</script>
<style scoped>
.edit-input {
padding-right: 100px;
}
.cancel-btn {
position: absolute;
right: 15px;
top: 10px;
}
</style>

View File

@@ -0,0 +1,251 @@
<!--
* @Author: zwq
* @Date: 2020-12-29 16:37:56
* @LastEditors: lb
* @LastEditTime: 2022-03-18 10:01:45
* @Description:
-->
<template>
<el-dialog :visible.sync="visible" :title="isedit ? 'btn.edit' : 'btn.add' | i18nFilter">
<!-- <span slot="title">
<small-title>
{{ isedit ? 'btn.edit' : 'btn.add' | i18nFilter }}
</small-title>
</span> -->
<el-form
ref="dataForm"
:model="dataForm"
:rules="dataRule"
label-width="100px"
@keyup.enter.native="dataFormSubmit()"
>
<el-form-item :label="$t('module.basicData.cache.ShelfType')" prop="dicDataId">
<el-select
v-model="dataForm.dicDataId"
:placeholder="$i18nForm(['placeholder.input', $t('module.basicData.cache.ShelfType')])"
clearable
class="lb-el-select"
>
<el-option v-for="item in dataTypes" :key="item.dataCode" :label="item.dataName" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item :label="$t('module.basicData.cache.ShelfName')" prop="name">
<el-input
v-model="dataForm.name"
:placeholder="$i18nForm(['placeholder.input', $t('module.basicData.cache.ShelfName')])"
clearable
/>
</el-form-item>
<el-form-item :label="$t('module.basicData.cache.ShelfCode')" prop="code">
<el-input
v-model="dataForm.code"
:placeholder="$i18nForm(['placeholder.input', $t('module.basicData.cache.ShelfCode')])"
clearable
/>
</el-form-item>
<el-form-item :label="$t('module.basicData.cache.ShelfAnotherCode')" prop="anotherCode">
<el-input
v-model="dataForm.anotherCode"
:placeholder="$i18nForm(['placeholder.input', $t('module.basicData.cache.ShelfAnotherCode')])"
clearable
/>
</el-form-item>
<el-form-item :label="$t('module.basicData.cache.ShelfAvailable')" prop="available">
<!-- 是否可用 -->
<el-switch v-model="shelfIsAvailable" />
</el-form-item>
<el-form-item :label="$t('module.basicData.cache.Notes')" prop="remark">
<!-- 备注 -->
<el-input
v-model="dataForm.remark"
type="textarea"
:rows="2"
:placeholder="$i18nForm(['placeholder.input', $t('module.basicData.cache.Notes')])"
clearable
@change="forceUpdate"
/>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="visible = false">{{ 'btn.cancel' | i18nFilter }}</el-button>
<el-button type="primary" @click="dataFormSubmit()">{{ 'btn.confirm' | i18nFilter }}</el-button>
</span>
</el-dialog>
</template>
<script>
import { detail, update, add, getCode, getAreaList, getDictListByType } from '@/api/basicData/Cache/shelf'
// import SmallTitle from '@/components/BaseDrawer/components/SmallTitle.vue'
export default {
// components: { SmallTitle },
props: {
areaId: {
type: String,
default: () => {
return ''
}
}
},
data() {
return {
statusChanged: false, // 启停状态是否变更
visible: false,
isPage: false,
dataTypes: [], // 所有类型
dataForm: {
//
id: 0,
dicDataId: '', // 选择的类型
name: '',
code: '',
anotherCode: '',
enabled: 0,
remark: '' // 后续可能要添加更多字段
},
areaArr: [],
dataRule: {
name: [
{
required: true,
message: this.$i18nForm(['placeholder.input', this.$t('module.basicData.cache.ShelfName')]),
trigger: 'blur'
}
],
code: [
{
required: true,
message: this.$i18nForm(['placeholder.input', this.$t('module.basicData.cache.ShelfCode')]),
trigger: 'blur'
}
],
dicDataId: [
{
required: true,
message: this.$i18nForm(['placeholder.input', this.$t('module.basicData.cache.ShelfType')]),
trigger: 'blur'
}
],
anotherCode: [
{
required: true,
message: this.$i18nForm(['placeholder.input', this.$t('module.basicData.cache.ShelfAnotherCode')]),
trigger: 'blur'
}
]
}
}
},
computed: {
shelfIsAvailable: {
get() {
return !!this.dataForm.enabled
},
set(val) {
// 此处仅通过更新内部的dataForm.enabled从而触发DOM视觉上的更新
// 并记录状态是否改变,但并不负责将更新同步至服务器
this.dataForm.enabled = val ? 1 : 0
this.statusChanged = true
}
}
},
methods: {
forceUpdate() {
// 为了解决输入框无法输入的问题
this.$forceUpdate()
},
init(id, isPage) {
this.isedit = !!id || false
this.statusChanged = false
this.isPage = isPage || false
this.dataForm.id = id || ''
if (!this.isPage) {
this.dataForm.areaId = this.areaId
}
this.areaArr.splice(0, this.areaArr.length)
const params = {
current: 1,
size: 500
}
getAreaList(params).then(response => {
if (response.data.records) {
this.areaArr = response.data.records
}
})
this.visible = true
this.$nextTick(() => {
this.$refs['dataForm'].resetFields()
// 通过货架的类型ID获取货架类型的字典列表
const HJTypeId = '1393401964580093950'
getDictListByType({
dictTypeId: HJTypeId,
current: 1,
size: 100 // 默认请求100条
}).then(res => {
this.dataTypes = res.data.records
})
if (this.dataForm.id) {
// 如果当前是编辑,则获取对应的货架信息
detail(this.dataForm.id).then(res => {
this.dataForm = res.data
})
} else {
// 如果当前是新增,则获取货架代码
getCode().then(res => {
this.dataForm.code = res.data
})
// 默认为可用
this.shelfIsAvailable = true
}
})
},
// 表单提交
dataFormSubmit() {
this.$refs['dataForm'].validate(valid => {
if (valid) {
const data = this.dataForm
if (this.dataForm.id) {
update(data).then(res => {
// 更新货架信息,并将'可用状态'的更新emit到父级
this.$message({
message: this.$t('module.basicData.visual.success'),
type: 'success',
duration: 1500,
onClose: () => {
this.visible = false
this.$emit('refreshDataList')
}
})
})
} else {
add(data).then(res => {
this.$message({
message: this.$t('module.basicData.visual.success'),
type: 'success',
duration: 1500,
onClose: () => {
this.visible = false
this.$emit('refreshDataList')
}
})
})
}
}
})
}
}
}
</script>
<style>
.lb-el-select {
width: 100%;
}
</style>

View File

@@ -0,0 +1,33 @@
<!--
* @Date: 2021-01-07 20:09:37
* @LastEditors: zwq
* @LastEditTime: 2021-03-06 13:03:40
* @FilePath: \basic-admin\src\components\BaseTable\subcomponents\CheckDetail.vue
* @Description:
-->
<template>
<span>
<el-button type="text" size="small" @click="emitClick">{{ $t('module.basicData.cache.ManageShelves') }}</el-button>
</span>
</template>
<script>
export default {
props: {
injectData: {
type: Object,
default: () => ({})
}
},
methods: {
emitClick() {
this.$router.push({
name: 'shelfAdd',
query: {
id: this.injectData.id
}
})
}
}
}
</script>

View File

@@ -0,0 +1,104 @@
<template>
<el-table
:data="tableData"
class="table"
:header-cell-style="headerStyle"
:row-class-name="setRowClass"
@cell-mouse-enter="showTooltip"
@cell-mouse-leave="hideTooltip"
@row-click="handleRowClick"
>
<el-table-column prop="_index" label="序号" width="55" align="center" />
<el-table-column prop="code" label="库位编码" width="180" align="center" />
<el-table-column prop="name" label="库位名称">
<template slot-scope="scope">
<el-tooltip
v-model="scope.row.showTooltip"
:disabled="!scope.row.showTooltip"
class="item"
effect="dark"
:content="scope.row.canSelect ? '点击选择' : '不可选择'"
placement="right"
>
<span>
{{ scope.row.name }}
</span>
</el-tooltip>
</template>
</el-table-column>
<el-table-column label="库位状态" width="90" align="center">
<template slot-scope="scope">
<div slot="content" style="display: flex; justify-content: center; align-items: center;">
<span class="enabled-icon" :class="{ 'enabled-icon-disabled': scope.row.canSelect !== true }" />
<span>
{{ scope.row.canSelect ? '可使用' : '已占用' }}
</span>
</div>
</template>
</el-table-column>
</el-table>
</template>
<script>
export default {
props: {
tableData: {
type: Array,
default: () => ([])
}
},
data() {
return {
headerStyle: {
// backgroundColor: '#ebebeb'
// backgroundColor: '#e9e9e9'
backgroundColor: '#fafafa',
color: '#000',
fontFamily: '微软雅黑',
fontWeight: 600
}
}
},
methods: {
showTooltip(row) {
row.showTooltip = true
},
hideTooltip(row) {
row.showTooltip = false
},
setRowClass({ row, rowIndex }) {
if (!row.canSelect) {
return 'row-disabled'
}
},
handleRowClick(row, column, event) {
if (row.canSelect) {
// console.log('点击了: ', { id: row.id, name: row.name })
this.$emit('stock-selected', { id: row.id, name: row.name })
}
}
}
}
</script>
<style scoped>
.test {
color: #ebebeb;
}
.enabled-icon {
width: 6px;
height: 6px;
margin-right: 6px;
border-radius: 50%;
background-color: #10dc76;
}
.enabled-icon-disabled {
background-color: #a8a8a8;
}
.table >>> .row-disabled {
color: #a8a8a8;
}
</style>

View File

@@ -0,0 +1,77 @@
<!--
* @Author: lb
* @Date: 2022-3-8 10:00:00
* @LastEditors: lb
* @LastEditTime: 2022-3-8 10:00:00
* @Description: 启停某个区域的状态
-->
<template>
<el-switch v-model="state" type="text" size="small" :disabled="readonly" @change="changeHandler" />
</template>
<script>
export default {
props: {
injectData: {
type: Object,
default: () => ({})
}
},
data() {
return {
state: false,
payload: {}
}
},
computed: {
readonly() {
return !!this.injectData.readonly
}
},
mounted() {
this.mapToState()
},
// watch: {
// "injectData.enabled": {
// handler: function (val) {
// this.state = !!this.injectData.enabled;
// },
// deep: true,
// },
// "injectData.currentStatus": {
// handler: function (val) {
// this.state = !!(this.injectData.currentStatus === 'true');
// },
// deep: true,
// },
// },
methods: {
mapToState() {
if (this.injectData.prop === 'currentStatus') {
this.state = !!(this.injectData[this.injectData.prop].toString().trim() === 'true')
return
} else {
// enabled
this.state = !!this.injectData['enabled']
return
}
},
changeHandler() {
if (this.injectData.prop === 'enabled') {
// 启停区域/缓存区
this.payload.id = this.injectData.id
this.payload.enabled = this.state ? 1 : 0
} else {
// 启停其他实体-该else分支后期可能会被删除
this.payload.id = this.injectData.id
this.payload.code = this.injectData.code
this.payload.name = this.injectData.name
this.payload.currentStatus = this.state
}
this.$emit('emitData', { action: 'toggleEnabled', data: this.payload })
}
}
}
</script>

View File

@@ -0,0 +1,164 @@
<!--
* @Author: lb
* @Date: 2022-03-23 15:00:00
* @LastEditors: lb
* @LastEditTime: 2022-05-16 09:33:37
-->
<template>
<el-dialog
:visible.sync="visible"
:append-to-body="true"
class="dialog"
custom-class="custom-dialog"
@closed="handleClosed"
>
<!-- :title="!isEdit ? 'btn.add' : 'btn.edit' | i18nFilter" -->
<div slot="title" class="dialog-title">
库位选择
</div>
<div class="dialog-body">
<div v-if="stockList.length === 0" style="text-align: center">该区域没有库位信息</div>
<div v-else>
<!-- 三张表格 -->
<triple-table :stock-list="stockList" :entires="30" @stock-selected="handleStockSelect" />
</div>
</div>
<div class="dialog-footer">
<el-checkbox v-show="false" v-model="onlyAvailable">仅看可用</el-checkbox>
<!-- 分页器 -->
<pagination
v-show="total > 0"
:total="total"
:page.sync="listQuery.current"
:limit.sync="listQuery.size"
:layout="'prev, pager, next, jumper'"
@pagination="getList()"
/>
</div>
</el-dialog>
</template>
<script>
import Pagination from '@/components/Pagination'
import { getAvailableStocks } from '@/api/basicData/Cache/storage'
import TripleTable from './triple-table.vue'
export default {
components: { TripleTable, Pagination },
props: {},
data() {
return {
loading: false,
visible: false,
stockList: [],
onlyAvailable: false,
total: 0,
listQuery: {
current: 1,
size: 30
},
baseinfo: null
}
},
methods: {
initListQuery() {
this.listQuery = {
current: 1,
size: 30 // 固定30条
}
},
// 初始化弹窗
init(data) {
this.initListQuery()
this.stockList.splice(0)
// 保存下数据
this.baseinfo = data
this.$nextTick(() => {
this.getList()
// 显示对话框
this.visible = true
})
},
getList() {
getAvailableStocks({ ...this.baseinfo, ...this.listQuery }).then(res => {
if (res.data.records) {
this.stockList = res.data.records
} else {
this.stockList.splice(0)
}
this.total = res.data.total
})
},
// 处理选中事件
handleStockSelect(data) {
this.$emit('stock-selected', data)
this.visible = false
},
// 弹窗关闭
handleClosed() {
this.$emit('handleClosed')
}
}
}
</script>
<style scoped>
/* 设置宽度自适应 */
.dialog >>> .custom-dialog {
display: inline-block;
left: 50%;
transform: translateX(-50%);
min-width: 50%;
max-width: 85vw;
width: unset;
}
.dialog >>> .el-dialog__body {
padding: 20px 30px;
}
.dialog-title {
padding: 8px;
font-size: 20px;
vertical-align: top;
}
.dialog-title::before {
content: '';
display: inline-block;
vertical-align: top;
width: 4px;
height: 20px;
border-radius: 2px;
background: #0b58ff;
margin-right: 4px;
}
.dialog-footer {
margin-top: 16px;
display: flex;
justify-content: flex-end;
/* 开启仅看可用功能时,需要使用: */
/* justify-content: space-between; */
align-items: center;
}
.dialog >>> .pagination-container {
padding: 0;
}
.dialog-footer >>> .el-pagination__jump {
margin-left: 12px;
}
.dialog-footer >>> .el-checkbox__input.is-checked .el-checkbox__inner {
background-color: #0b58ff;
border-color: #0b58ff;
}
.dialog-footer >>> .el-checkbox__input.is-checked + .el-checkbox__label {
color: #0b58ff;
}
</style>

View File

@@ -0,0 +1,65 @@
<!--
* @Author: lb
* @Date: 2022-05-12 16:00:00
* @LastEditors: lb
* @LastEditTime: 2022-05-12 16:00:00
-->
<template>
<el-dialog
v-loading.fullscreen.lock="loading"
element-loading-spinner="el-icon-loading"
element-loading-text="拼命加载中"
element-loading-background="rgba(255, 255, 255, 0.1)"
:title="!isEdit ? 'btn.add' : 'btn.edit' | i18nFilter"
:visible.sync="visible"
@closed="handleClosed"
>
<!-- 填充内容库位列表 -->
<!-- 双击事件 @emit 库位信息 -->
<span slot="footer" class="dialog-footer">
<el-button @click="initStorageForm">{{ 'btn.reset' | i18nFilter }}</el-button>
<el-button type="primary" @click="submit">{{ 'btn.confirm' | i18nFilter }}</el-button>
</span>
</el-dialog>
</template>
<script>
// import { getStockList } from '@/api/basicData/Cache/storage'
/** 请求参数配置 - 后续或许会需要更改 */
// const stockListQueryParams = {
// current: 1,
// size: 100
// }
export default {
props: {},
data() {
return {
loading: false,
visible: false,
stockList: []
}
},
methods: {
// 初始化弹窗
init() {
// 显示对话框
this.visible = true
this.$nextTick(() => {})
},
pickStock(data) {
// 把所选的库位传到外面
// data.id
// data.name
this.$emit('stockPicked', data)
},
// 弹窗关闭
handleClosed() {
this.$emit('handleClosed')
}
}
}
</script>

View File

@@ -0,0 +1,396 @@
<!--
* @Author: lb
* @Date: 2022-03-23 15:00:00
* @LastEditors: lb
* @LastEditTime: 2022-03-28 8:30:00
-->
<template>
<el-dialog
v-loading.fullscreen.lock="loading"
element-loading-spinner="el-icon-loading"
element-loading-text="拼命加载中"
element-loading-background="rgba(255, 255, 255, 0.1)"
:title="!isEdit ? 'btn.add' : 'btn.edit' | i18nFilter"
:visible.sync="visible"
@closed="handleClosed"
>
<div style="text-align: center">
<el-form
ref="storageForm"
:inline="true"
:model="storageForm"
:rules="storageValidationRules"
label-width="100px"
@keyup.enter.native="submit"
>
<!-- 方式 -->
<el-form-item :label="$t('module.basicData.cache.OperateType')" prop="operateType">
<el-select
v-model="storageForm.operateType"
:placeholder="$i18nForm(['placeholder.input', $t('module.basicData.cache.OperateType')])"
clearable
style="width:247px"
>
<el-option :label="$t('module.basicData.cache.Export')" :value="1" />
<el-option :label="$t('module.basicData.cache.Import')" :value="2" />
</el-select>
</el-form-item>
<!-- 货架编码 -->
<el-form-item :label="$t('module.basicData.cache.ShelfCode')" prop="shelfId">
<el-select
v-model="storageForm.shelfId"
filterable
:placeholder="$i18nForm(['placeholder.input', $t('module.basicData.cache.ShelfCode')])"
clearable
style="width:247px"
>
<el-option v-for="sCode in shelfList" :key="sCode.id" :label="sCode.code" :value="sCode.id" />
</el-select>
</el-form-item>
<!-- 缓存区 -->
<el-form-item :label="$t('module.basicData.cache.CacheNameAbbr')" prop="cacheId">
<el-select
v-model="storageForm.cacheId"
clearable
:placeholder="$i18nForm(['placeholder.input', $t('module.basicData.cache.CacheNameAbbr')])"
style="width:247px"
>
<el-option v-for="item in cacheList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<!-- 区域 -->
<el-form-item :label="$t('module.basicData.cache.AreaAbbr')" prop="areaId">
<el-select
v-model="storageForm.areaId"
filterable
clearable
:disabled="!storageForm.cacheId"
:placeholder="$i18nForm(['placeholder.input', $t('module.basicData.cache.AreaAbbr')])"
style="width:247px"
>
<el-option v-for="item in areaList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<!-- 库位 -->
<el-form-item :label="$t('module.basicData.cache.StorageLocation')" prop="stockId">
<!-- <el-select
v-model="storageForm.stockId"
clearable
:disabled="!storageForm.areaId"
:placeholder="$i18nForm(['placeholder.input', $t('module.basicData.cache.StorageLocation')])"
style="width:247px"
>
<el-option v-for="item in stockList" :key="item.id" :label="item.name" :value="item.id" />
</el-select> -->
<!-- 不用采用下拉框的形式了 -->
<el-button type="text" @click="openStockDialog">查看库位</el-button>
</el-form-item>
<!-- 产品物料名 -->
<el-form-item :label="$t('module.basicData.cache.ProductAndMaterialName')" prop="semifinishedProductId">
<el-select
v-model="storageForm.semifinishedProductId"
filterable
clearable
:placeholder="$i18nForm(['placeholder.input', $t('module.basicData.cache.ProductAndMaterialName')])"
style="width:247px"
@change="$forceUpdate()"
>
<el-option v-for="item in productList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<!-- 产品规格 -->
<el-form-item :label="$t('module.basicData.cache.ProductSpecs')">
<el-input
v-model="productSpecifications"
:placeholder="$i18nForm(['placeholder.input', $t('module.basicData.cache.ProductSpecs')])"
style="width:247px"
/>
</el-form-item>
<!-- 数量 -->
<el-form-item :label="$t('module.basicData.cache.Quantity')" prop="num">
<el-input-number
v-model.number="storageForm.num"
style="width:247px"
type="number"
:min="1"
:step="1"
:placeholder="$i18nForm(['placeholder.input', $t('module.basicData.cache.Quantity')])"
clearable
/>
</el-form-item>
</el-form>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="initStorageForm">{{ 'btn.reset' | i18nFilter }}</el-button>
<el-button type="primary" @click="submit">{{ 'btn.confirm' | i18nFilter }}</el-button>
</span>
</el-dialog>
</template>
<script>
// import Vue from 'vue'
import {
getShelfList,
getCacheList,
getAreaList,
getStockList,
getProductsList,
detail,
update,
add
} from '@/api/basicData/Cache/storage'
/** 请求参数配置 - 后续或许会需要更改 */
const shelfListQueryParams = {
current: 1,
size: 100
}
const cacheListQueryParams = shelfListQueryParams
const areaListQueryParams = shelfListQueryParams
const stockListQueryParams = shelfListQueryParams
const productsListQueryParams = shelfListQueryParams
const storageValidationRules = {
operateType: {
required: true,
type: 'enum',
enum: [1, 2],
// message: () => this.$t('')
message: '出入库为必选项',
trigger: 'change'
},
cacheId: { required: true, message: '缓存区必填', trigger: 'change' },
areaId: { required: true, message: '区域必填', trigger: 'change' },
stockId: { required: true, message: '库位必填', trigger: 'change' },
shelfId: { required: true, message: '货架必填', trigger: 'change' },
semifinishedProductId: { required: true, message: '产品必填', trigger: 'change' },
num: { required: true, message: '数量大于1', trigger: 'blur' }
}
export default {
props: {},
data() {
return {
loading: false,
storageValidationRules,
isEdit: false,
visible: false,
storageForm: {
// 出入库的表单
id: null,
operateType: 1, // 默认1出库2入库
stockId: '', // 库位id
shelfId: '', // 货架id
semifinishedProductId: '', // 产品id
source: 0, // 来源
num: 0, // 数量
remark: '', // 备注始终为空,后端没实现该字段
cacheId: '',
areaId: ''
},
temporaryForm: {},
productSpecifications: null,
productList: [],
cacheList: [],
areaList: [],
stockList: [],
shelfList: [],
allowWatch: false,
finishedRequest: 0 // 编辑页面中,异步完成的请求数
}
},
watch: {
finishedRequest(val) {
// 监听异步请求完成数量,如果完成了 5 个,代表所有请求都已完成
if (val === 5) {
this.$emit('allListLoaded') // 在 created() 中监听此事件
}
},
'storageForm.cacheId': function(val, oldVal) {
// 只在新增模式下观察
if ((!this.isEdit || this.allowWatch) && val && val !== oldVal) {
this.loading = true
getAreaList({
...areaListQueryParams,
cacheId: val
}).then(response => {
this.areaList.splice(0, this.areaList.length)
this.storageForm.areaId = null
if (response.data.records) {
this.areaList = response.data.records
this.$emit('oneRequestComplete')
}
this.loading = false
})
}
},
'storageForm.areaId': function(val, oldVal) {
// 只在新增模式下观察
if ((!this.isEdit || this.allowWatch) && val && val !== oldVal) {
// 请求 stockList
this.loading = true
// ==> 这里可能需要修改了,需将 areaId/cacheId 传入新的库位列表弹窗
getStockList({
...stockListQueryParams,
areaId: val
}).then(response => {
this.storageForm.stockId = null
this.stockList.splice(0, this.stockList.length)
if (response.data.records) {
this.stockList = response.data.records
}
this.loading = false
})
}
},
'storageForm.semifinishedProductId': {
handler: function(val, oldVal) {
if (val && val !== oldVal) {
// 获得规格描述,直接从本地 productList 里筛选出来
const chosenProduct = this.productList.find(obj => obj.id === val)
this.productSpecifications = chosenProduct.specifications || ''
}
},
deep: true,
immediate: true
}
},
mounted() {
this.$on('allListLoaded', this.fillTheEditForm)
this.$on('oneRequestComplete', () => {
this.finishedRequest += 1
})
},
methods: {
openStockDialog(data) {
// 打开库位列表
// data 包含缓存区和区域相关信息,用于定位库位列表
},
handleStockPicked(data) {
// 处理选择库位的事件
// data 应该包含所选的库位信息,或要能定位库位
},
// 填充编辑表单
fillTheEditForm() {
this.storageForm = this.temporaryForm
this.$set(this.storageForm, 'semifinishedProductId', this.temporaryForm.productId)
this.loading = false
this.$nextTick(() => {
this.allowWatch = true
})
},
// 初始化出入库表单
initStorageForm() {
this.storageForm.id = null
this.storageForm.operateType = 1
this.storageForm.stockId = null
this.storageForm.shelfId = null
this.storageForm.semifinishedProductId = null
this.storageForm.source = 0 // 一直默认0手动
this.storageForm.num = 1 // 不能为负数和0需要在验证器里添加验证
this.storageForm.remark = ''
this.storageForm.cacheId = null
this.storageForm.areaId = null
this.productSpecifications = ''
},
// 初始化弹窗
init(storageId) {
// 显示对话框
this.visible = true
this.$nextTick(() => {
if (storageId) {
this.loading = true
this.isEdit = true
// 默认关闭 watch 功能
this.allowWatch = false
// 如果是编辑
detail(storageId).then(response => {
// 把后端数据存入一个临时的表单对象里
// 等万事俱备时再将这个临时表单的内容填入 storageForm 展现到页面上
this.temporaryForm = response.data
// 异步请求
// shelf数据cache数据area数据
// stock数据product数据
getShelfList({ ...shelfListQueryParams, enabled: 1 }).then(r => {
this.shelfList.splice(0, this.shelfList.length)
if (r.data.records) this.shelfList = r.data.records
this.$emit('oneRequestComplete')
})
getCacheList({ ...cacheListQueryParams }).then(r => {
this.cacheList.splice(0, this.cacheList.length)
if (r.data.records) this.cacheList = r.data.records
this.$emit('oneRequestComplete')
})
getAreaList({ ...areaListQueryParams, cacheId: this.temporaryForm.cacheId }).then(r => {
this.areaList.splice(0, this.areaList.length)
if (r.data.records) this.areaList = r.data.records
this.$emit('oneRequestComplete')
})
getStockList({ ...stockListQueryParams, areaId: this.temporaryForm.areaId }).then(r => {
this.stockList.splice(0, this.stockList.length)
if (r.data.records) this.stockList = r.data.records
this.$emit('oneRequestComplete')
})
getProductsList({ ...productsListQueryParams, enabled: 1 }).then(r => {
this.productList.splice(0, this.productList.length)
if (r.data.records) this.productList = r.data.records
this.$emit('oneRequestComplete')
})
})
} else {
this.isEdit = false
// 新增时,只用获取下面这些列表即可:
// 拉取货架列表
getShelfList({ ...shelfListQueryParams, enabled: 1 }).then(response => {
this.shelfList.splice(0, this.shelfList.length)
if (response.data.records) this.shelfList = response.data.records
})
// 拉取缓存区列表
getCacheList(cacheListQueryParams).then(response => {
this.cacheList.splice(0, this.cacheList.length)
if (response.data.records) this.cacheList = response.data.records
})
// 拉取产品列表
getProductsList({ ...productsListQueryParams, enabled: 1 }).then(response => {
this.productList.splice(0, this.productList.length)
if (response.data.records) this.productList = response.data.records
})
}
})
},
// 提交出入库表单
submit() {
this.$refs['storageForm'].validate(valid => {
if (valid) {
const ajaxAction = this.isEdit ? update : add
ajaxAction(this.storageForm).then(response => {
this.$message({
message: this.$t('module.basicData.visual.success'),
type: 'success',
duration: 1500,
onClose: () => {
this.visible = false
this.$emit('refreshDataList')
}
})
})
}
})
},
// 弹窗关闭
handleClosed() {
this.$emit('handleClosed')
}
}
}
</script>

View File

@@ -0,0 +1,601 @@
<!--
* @Author: lb
* @Date: 2022-05-16 09:33:37
* @LastEditors: lb
* @LastEditTime: 2022-05-16 09:33:37
* @specifications: 出入库编辑-抽屉结构
-->
<template>
<el-drawer :visible.sync="visible" :show-close="false" :wrapper-closable="false" class="drawer">
<div slot="title" class="drawer-title">
<!-- {{ isdetail ? 'btn.detail' : !storageForm.id ? 'btn.add' : 'btn.edit' | i18nFilter }} -->
出入库填写
</div>
<div style="margin:0 64px">
<el-form
ref="storageForm"
:model="storageForm"
:rules="dataRule"
label-width="100px"
label-position="top"
@keyup.enter.native="dataFormSubmit"
>
<el-row :gutter="50">
<!-- 第一列 -->
<el-col :span="12">
<el-row>
<!-- 方式 -->
<el-form-item :label="$t('module.basicData.cache.OperateType')" prop="operateType">
<el-select
v-model="storageForm.operateType"
:placeholder="$i18nForm(['placeholder.input', $t('module.basicData.cache.OperateType')])"
clearable
>
<el-option :label="$t('module.basicData.cache.Export')" :value="1" />
<el-option :label="$t('module.basicData.cache.Import')" :value="2" />
</el-select>
</el-form-item>
</el-row>
<el-row>
<!-- 缓存区 -->
<el-form-item :label="$t('module.basicData.cache.CacheNameAbbr')" prop="cacheId">
<el-select
v-model="storageForm.cacheId"
clearable
:placeholder="$i18nForm(['placeholder.input', $t('module.basicData.cache.CacheNameAbbr')])"
>
<el-option v-for="item in cacheList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
</el-row>
<el-row>
<!-- 库位 -->
<el-form-item :label="$t('module.basicData.cache.StorageLocation')" prop="stockId">
<div class="el-form-item__content">
<button
class="stock-btn"
:class="{ 'stock-disabled': !storageForm.areaId, 'stock-enabled': storageForm.areaId }"
@click.prevent.stop="openStockDialog"
>
<span class="stock-btn__text">
{{ selectedStock ? selectedStock : $i18nForm(['placeholder.input', $t('module.basicData.cache.Location')]) }}
</span>
<span class="stock-btn__icon">
<svg
width="65%"
height="65%"
viewBox="0 0 14 14"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
>
<title>弹窗</title>
<g id="仓库管理" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="出入库操作_新增" transform="translate(-1641.000000, -374.000000)">
<g id="编组-19" transform="translate(1448.000000, 0.000000)">
<g id="编组-15" transform="translate(56.000000, 341.000000)">
<g id="单独-32-备份" transform="translate(0.000000, 24.000000)">
<g id="编组" transform="translate(136.000000, 8.000000)">
<rect
id="矩形"
fill="#000000"
fill-rule="nonzero"
opacity="0"
x="0"
y="0"
width="16"
height="16"
/>
<g id="工单下发备份" fill-rule="nonzero">
<rect id="矩形" fill="#000000" opacity="0" x="0" y="0" width="16" height="16" />
<path
id="形状结合"
d="M13.0438556,1.20937158 C13.2588773,1.20937158 13.4620313,1.26372912 13.6397417,1.35989534 C13.8001729,1.44729129 13.9368068,1.56547787 14.0439848,1.70683585 C14.0574819,1.72469691 14.0704621,1.74280568 14.0829665,1.76127119 C14.1201606,1.81644256 14.1513042,1.8710832 14.1782718,1.92803778 C14.2030362,1.98070901 14.2242847,2.03507227 14.2417389,2.09118375 L14.2730699,2.21241367 C14.2896612,2.29375583 14.2983584,2.37786569 14.2983584,2.4638744 L14.2983584,2.4638744 L14.2983584,13.5359655 L14.2918811,13.6642242 C14.2276335,14.296785 13.6933564,14.7904683 13.0438556,14.7904683 L13.0438556,14.7904683 L8.07874437,14.7904683 L7.99964162,14.7833716 L7.92125563,14.7904683 L2.95614444,14.7904683 C2.30664357,14.7904683 1.77236646,14.296785 1.70811893,13.6642242 L1.70164162,13.5359655 L1.70164162,2.4638744 C1.70164162,2.20584828 1.77991647,1.96491181 1.91478176,1.76452387 C1.9676768,1.68648532 2.02612316,1.61755083 2.09115852,1.55558994 C2.1703925,1.48009344 2.25985438,1.41462726 2.35729285,1.36160585 C2.53796872,1.26372912 2.74112267,1.20937158 2.95614444,1.20937158 L2.95614444,1.20937158 L13.0438556,1.20937158 Z M7.99964162,5.63437158 L2.76364162,5.65837158 L2.76524387,13.4758909 C2.76524387,13.5948261 2.84779995,13.6943729 2.95876835,13.7203876 L3.01636958,13.7270166 L7.93119278,13.7270166 L7.99964162,13.7313716 L8.06880722,13.7270166 L12.9836304,13.7270166 L13.0412317,13.7203876 C13.1522001,13.6943729 13.2347561,13.5948261 13.2347561,13.4758909 L13.2347561,13.4758909 L13.2356416,5.65837158 L7.99964162,5.63437158 Z M13.0438556,2.27297383 L2.95614444,2.27297383 C2.93161206,2.27297383 2.90797392,2.27768001 2.88621631,2.28615171 C2.81562722,2.31403543 2.76524387,2.38323471 2.76524387,2.4638744 L2.76524387,2.4638744 L2.76464162,4.59837158 L7.99964162,4.62337158 L13.2346416,4.59837158 L13.2347561,2.4638744 L13.2266826,2.4089277 C13.2030025,2.33040279 13.1299491,2.27297383 13.0438556,2.27297383 Z"
:fill="!storageForm.areaId ? '#BFBFBF' : '#115CFF'"
/>
</g>
<rect
id="矩形"
stroke="#979797"
fill="#D8D8D8"
opacity="0"
x="0.5"
y="0.5"
width="15"
height="15"
/>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>
</span>
</button>
</div>
</el-form-item>
</el-row>
<el-row>
<!-- 产品规格 -->
<el-form-item :label="$t('module.basicData.cache.ProductSpecs')">
<el-input
v-model="productSpecifications"
disabled
:placeholder="$i18nForm(['placeholder.input', $t('module.basicData.cache.ProductSpecs')])"
/>
</el-form-item>
</el-row>
</el-col>
<!-- 第二列 -->
<el-col :span="12">
<el-row>
<!-- 货架编码 -->
<el-form-item :label="$t('module.basicData.cache.ShelfCode')" prop="shelfId">
<el-select
v-model="storageForm.shelfId"
filterable
:placeholder="$i18nForm(['placeholder.input', $t('module.basicData.cache.ShelfCode')])"
clearable
>
<el-option v-for="sCode in shelfList" :key="sCode.id" :label="sCode.code" :value="sCode.id" />
</el-select>
</el-form-item>
</el-row>
<el-row>
<!-- 区域 -->
<el-form-item :label="$t('module.basicData.cache.AreaAbbr')" prop="areaId">
<el-select
v-model="storageForm.areaId"
filterable
clearable
:disabled="!storageForm.cacheId"
:placeholder="$i18nForm(['placeholder.input', $t('module.basicData.cache.AreaAbbr')])"
>
<el-option v-for="item in areaList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
</el-row>
<el-row>
<!-- 产品物料名 -->
<el-form-item :label="$t('module.basicData.cache.ProductAndMaterialName')" prop="semifinishedProductId">
<el-select
v-model="storageForm.semifinishedProductId"
filterable
clearable
:placeholder="$i18nForm(['placeholder.input', $t('module.basicData.cache.ProductAndMaterialName')])"
>
<el-option v-for="item in productList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
</el-row>
<el-row>
<!-- 数量 -->
<el-form-item :label="$t('module.basicData.cache.Quantity')" prop="num">
<el-input
v-model="storageForm.num"
:min="1"
:step="1"
:placeholder="$i18nForm(['placeholder.input', $t('module.basicData.cache.Quantity')])"
clearable
/>
</el-form-item>
</el-row>
</el-col>
</el-row>
</el-form>
<div style="position: absolute; bottom: 24px; right: 24px;">
<el-button @click="goback()">{{ 'btn.cancel' | i18nFilter }}</el-button>
<el-button type="primary" @click="submit()">{{ 'btn.confirm' | i18nFilter }}</el-button>
<!-- <el-button @click="goback()">{{ 'btn.back' | i18nFilter }}</el-button>
<el-button v-if="isdetail" type="primary" @click="goEdit()">{{ 'btn.edit' | i18nFilter }}</el-button>
<span v-if="!isdetail">
<el-button type="primary" @click="dataFormSubmit()">{{ 'btn.save' | i18nFilter }}</el-button>
<el-button v-if="storageForm.id && !isdetail" type="primary" @click="addNew()">
{{ 'btn.addattr' | i18nFilter }}
</el-button>
</span> -->
</div>
<!-- <base-table
:page="listQuery.current"
:limit="listQuery.size"
:table-config="tableProps"
:table-data="productAttributeList"
>
<method-btn v-if="!isdetail" slot="handleBtn" :method-list="tableBtn" @clickBtn="handleClick" />
</base-table>
<pagination
v-show="total > 0"
:total="total"
:page.sync="listQuery.current"
:limit.sync="listQuery.size"
:page-sizes="[5, 10, 15]"
@pagination="getList"
/> -->
</div>
<stock-dialog v-if="addOrUpdateVisible" ref="addOrUpdate" @stock-selected="handleStockChange" />
</el-drawer>
</template>
<script>
// import Vue from 'vue'
import {
getShelfList,
getCacheList,
getAreaList,
// getStockList,
getProductsList,
detail,
update,
add
} from '@/api/basicData/Cache/storage'
import StockDialog from './stock-dialog.vue'
/** 请求参数配置 - 后续或许会需要更改 */
const shelfListQueryParams = {
current: 1,
size: 100
}
const cacheListQueryParams = shelfListQueryParams
const areaListQueryParams = shelfListQueryParams
// const stockListQueryParams = shelfListQueryParams
const productsListQueryParams = shelfListQueryParams
const storageValidationRules = {
operateType: {
required: true,
type: 'enum',
enum: [1, 2],
// message: () => this.$t('')
message: '出入库为必选项',
trigger: 'change'
},
cacheId: { required: true, message: '缓存区必填', trigger: 'change' },
areaId: { required: true, message: '区域必填', trigger: 'change' },
stockId: { required: true, message: '库位必填', trigger: 'change' },
shelfId: { required: true, message: '货架必填', trigger: 'change' },
semifinishedProductId: { required: true, message: '产品必填', trigger: 'change' },
num: { required: true, message: '数量大于1', trigger: 'blur' }
}
export default {
components: { StockDialog },
props: {},
data() {
return {
loading: false,
storageValidationRules,
isEdit: false,
visible: false,
addOrUpdateVisible: false,
dataRule: {},
selectedStock: '',
storageForm: {
// 出入库的表单
id: null,
operateType: 1, // 默认1出库2入库
stockId: '', // 库位id
shelfId: '', // 货架id
semifinishedProductId: '', // 产品id
source: 0, // 来源
num: 0, // 数量
remark: '', // 备注始终为空,后端没实现该字段
cacheId: '',
areaId: ''
},
temporaryForm: {},
productSpecifications: null,
productList: [],
cacheList: [],
areaList: [],
// stockList: [],
shelfList: [],
allowWatch: false,
finishedRequest: 0 // 编辑页面中,异步完成的请求数
}
},
watch: {
finishedRequest(val) {
// 监听异步请求完成数量,如果完成了 5 个,代表所有请求都已完成
if (val === 4) {
this.$emit('allListLoaded') // 在 created() 中监听此事件
this.finishedRequest = 0
}
},
'storageForm.cacheId': function(val, oldVal) {
// 只在新增模式下观察
if ((!this.isEdit || this.allowWatch) && val && val !== oldVal) {
this.loading = true
getAreaList({
...areaListQueryParams,
cacheId: val
}).then(response => {
this.areaList.splice(0, this.areaList.length)
this.storageForm.areaId = null
if (response.data.records) {
this.areaList = response.data.records
this.$emit('oneRequestComplete')
}
this.loading = false
})
}
},
// 'storageForm.areaId': function(val, oldVal) {
// // 只在新增模式下观察
// if ((!this.isEdit || this.allowWatch) && val && val !== oldVal) {
// // 请求 stockList
// this.loading = true
// // ==> 这里可能需要修改了,需将 areaId/cacheId 传入新的库位列表弹窗
// getStockList({
// ...stockListQueryParams,
// areaId: val
// }).then(response => {
// this.storageForm.stockId = null
// this.stockList.splice(0, this.stockList.length)
// if (response.data.records) {
// this.stockList = response.data.records
// }
// this.loading = false
// })
// }
// },
'storageForm.semifinishedProductId': {
handler: function(val, oldVal) {
if (val && val !== oldVal) {
// 获得规格描述,直接从本地 productList 里筛选出来
const chosenProduct = this.productList.find(obj => obj.id === val)
this.productSpecifications = chosenProduct.specifications || ''
}
},
deep: true,
immediate: true
}
},
mounted() {
this.$on('allListLoaded', this.fillTheEditForm)
this.$on('oneRequestComplete', () => {
this.finishedRequest += 1
})
},
methods: {
openStockDialog() {
if (this.storageForm.areaId) {
// 如果允许选择库位
this.addOrUpdateVisible = true
this.$nextTick(() => {
this.$refs.addOrUpdate.init({
cacheId: this.storageForm.cacheId,
areaId: this.storageForm.areaId,
operateType: this.storageForm.operateType
})
})
}
},
// 填充编辑表单
fillTheEditForm() {
this.storageForm = this.temporaryForm
// 填充库位名
this.selectedStock = this.temporaryForm.stockName ? this.temporaryForm.stockName : ''
this.productSpecifications = this.temporaryForm.specifications ? this.temporaryForm.specifications : ''
// console.log('temporaryForm', this.temporaryForm)
this.$set(this.storageForm, 'semifinishedProductId', this.temporaryForm.productId)
this.loading = false
this.$nextTick(() => {
this.allowWatch = true
})
},
// 初始化出入库表单
initStorageForm() {
this.storageForm.id = null
this.storageForm.operateType = 1
this.storageForm.stockId = null
this.storageForm.shelfId = null
this.storageForm.semifinishedProductId = null
this.storageForm.source = 0 // 一直默认0手动
this.storageForm.num = 1 // 不能为负数和0需要在验证器里添加验证
this.storageForm.remark = ''
this.storageForm.cacheId = null
this.storageForm.areaId = null
this.productSpecifications = ''
this.selectedStock = ''
},
// 初始化弹窗
init(storageId) {
this.initStorageForm()
// 显示对话框
this.visible = true
this.$nextTick(() => {
if (storageId) {
this.loading = true
this.isEdit = true
// 默认关闭 watch 功能
this.allowWatch = false
// 如果是编辑
detail(storageId).then(response => {
// 把后端数据存入一个临时的表单对象里
// 等万事俱备时再将这个临时表单的内容填入 storageForm 展现到页面上
this.temporaryForm = response.data
// 异步请求
// shelf数据cache数据area数据
// stock数据product数据
getShelfList({ ...shelfListQueryParams, enabled: 1 }).then(r => {
this.shelfList.splice(0)
if (r.data.records) this.shelfList = r.data.records
this.$emit('oneRequestComplete')
})
getCacheList({ ...cacheListQueryParams }).then(r => {
this.cacheList.splice(0)
if (r.data.records) this.cacheList = r.data.records
this.$emit('oneRequestComplete')
})
getAreaList({ ...areaListQueryParams, cacheId: this.temporaryForm.cacheId }).then(r => {
this.areaList.splice(0)
if (r.data.records) this.areaList = r.data.records
this.$emit('oneRequestComplete')
})
// getStockList({ ...stockListQueryParams, areaId: this.temporaryForm.areaId }).then(r => {
// this.stockList.splice(0)
// if (r.data.records) this.stockList = r.data.records
// this.$emit('oneRequestComplete')
// })
getProductsList({ ...productsListQueryParams, enabled: 1 }).then(r => {
this.productList.splice(0)
if (r.data.records) this.productList = r.data.records
this.$emit('oneRequestComplete')
})
})
} else {
this.isEdit = false
// 新增时,只用获取下面这些列表即可:
// 拉取货架列表
getShelfList({ ...shelfListQueryParams, enabled: 1 }).then(response => {
this.shelfList.splice(0, this.shelfList.length)
if (response.data.records) this.shelfList = response.data.records
})
// 拉取缓存区列表
getCacheList(cacheListQueryParams).then(response => {
this.cacheList.splice(0, this.cacheList.length)
if (response.data.records) this.cacheList = response.data.records
})
// 拉取产品列表
getProductsList({ ...productsListQueryParams, enabled: 1 }).then(response => {
this.productList.splice(0, this.productList.length)
if (response.data.records) this.productList = response.data.records
})
}
})
},
// 选择库位
handleStockChange({ id, name }) {
this.storageForm.stockId = id
this.selectedStock = name
},
// 提交出入库表单
submit() {
this.$refs['storageForm'].validate(valid => {
if (valid) {
const ajaxAction = this.isEdit ? update : add
ajaxAction(this.storageForm).then(response => {
this.$message({
message: this.$t('module.basicData.visual.success'),
type: 'success',
duration: 1500,
onClose: () => {
this.visible = false
this.$emit('refreshDataList')
}
})
})
}
})
},
// 弹窗关闭
handleClosed() {
this.$emit('handleClosed')
},
goback() {
this.$emit('refreshDataList')
this.visible = false
}
}
}
</script>
<style scoped>
.drawer >>> .el-drawer {
border-radius: 8px 0 0 8px;
}
.drawer >>> .el-form-item__label {
padding: 0;
}
.drawer >>> .el-drawer__header {
margin: 0;
padding: 32px 32px 24px;
border-bottom: 1px solid #dcdfe6;
margin-bottom: 30px;
}
/* .drawer >>> .el-drawer__body {
margin-top: 0;
} */
.drawer-title {
font-weight: 500;
font-size: 22px;
color: #000;
font-family: '微软雅黑', 'Microsoft YaHei', Arial, Helvetica, sans-serif;
}
.drawer-title::before {
content: '';
background: #0b58ff;
display: inline-block;
width: 4px;
height: 25px;
vertical-align: top;
margin-right: 6px;
border-radius: 2px;
}
.stock-btn {
outline: none;
border-radius: 4px;
background-color: #fff;
border: 1px solid #dcdfe6;
width: 100%;
height: 34px;
line-height: 34px;
padding: 0 5px 0 15px;
display: flex;
justify-content: center;
align-items: center;
transition: box-shadow 0.3s ease-out;
}
/*
.stock-btn:not([class*='stock-disabled']):hover {
cursor: pointer;
border-color: #ccc;
box-shadow: 0 0 3px 1px rgba(0, 0, 0, 0.2);
} */
.stock-btn__text {
text-align: left;
flex: 1 auto;
overflow: hidden;
margin-right: 5px;
}
.stock-btn__icon {
flex-shrink: 0;
height: 30px;
width: 30px;
display: flex;
justify-content: center;
align-items: center;
}
.stock-enabled {
/* color: #115cff; */
/* background-color: #e9e9e9; */
}
.stock-disabled {
color: #ccc;
background-color: #f5f7fa;
cursor: not-allowed;
}
.stock-disabled svg {
color: #ccc;
background-color: #f5f7fa;
cursor: not-allowed;
}
</style>

View File

@@ -0,0 +1,146 @@
<!--
* @Author: zwq
* @Date: 2020-12-29 16:37:56
* @LastEditors: zwq
* @LastEditTime: 2021-07-21 13:59:43
* @Description:
-->
<template>
<el-dialog
:title="!dataForm.id ? 'btn.add' : 'btn.edit' | i18nFilter"
:visible.sync="visible"
>
<el-form ref="dataForm" :model="dataForm" :rules="dataRule" label-width="100px" @keyup.enter.native="dataFormSubmit()">
<el-form-item :label="$t('module.basicData.storageBox.name')" prop="name">
<el-input v-model="dataForm.name" :placeholder="$i18nForm(['placeholder.input', $t('module.basicData.storageBox.name')])" clearable />
</el-form-item>
<el-form-item :label="$t('module.basicData.storageBox.code')" prop="code">
<el-input v-model="dataForm.code" :placeholder="$i18nForm(['placeholder.input', $t('module.basicData.storageBox.code')])" clearable />
</el-form-item>
<el-form-item :label="$t('module.basicData.storageBox.StorageQuantity')" prop="quantity">
<el-input-number v-model="dataForm.quantity" :min="0" :placeholder="$i18nForm(['placeholder.input', $t('module.basicData.storageBox.StorageQuantity')])" />
</el-form-item>
<el-form-item :label="$t('module.basicData.storageBox.alias')" prop="aliasName">
<el-input v-model="dataForm.aliasName" :placeholder="$i18nForm(['placeholder.input', $t('module.basicData.storageBox.alias')])" clearable />
</el-form-item>
<el-form-item :label="$t('module.basicData.storageBox.status')" prop="status">
<el-select v-model="dataForm.status" :placeholder="$i18nForm(['placeholder.input', $t('module.basicData.storageBox.status')])" clearable>
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item :label="$t('module.basicData.visual.Remarks')" prop="remark">
<el-input v-model="dataForm.remark" :placeholder="$i18nForm(['placeholder.input', $t('module.basicData.visual.Remarks')])" clearable />
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="visible = false">{{ 'btn.cancel' | i18nFilter }}</el-button>
<el-button type="primary" @click="dataFormSubmit()">{{ 'btn.confirm' | i18nFilter }}</el-button>
</span>
</el-dialog>
</template>
<script>
import { storageBoxDetail, storageBoxUpdate, storageBoxAdd, storageBoxCode } from '@/api/basicData/Cache/storageBox'
export default {
data() {
return {
visible: false,
dataForm: {
id: 0,
name: '',
code: '',
status: 0,
aliasName: '',
quantity: 0,
remark: ''
},
options: [
{
value: 0,
label: '正常'
},
{
value: 1,
label: '维修中'
},
{
value: 2,
label: '报废'
}
],
dataRule: {
name: [
{
required: true,
message: this.$i18nForm(['placeholder.input', this.$t('module.basicData.storageBox.name')]),
trigger: 'blur' }
],
code: [
{
required: true,
message: this.$i18nForm(['placeholder.input', this.$t('module.basicData.storageBox.code')]),
trigger: 'blur' }
]
}
}
},
methods: {
init(id) {
this.dataForm.id = id || ''
this.visible = true
this.$nextTick(() => {
this.$refs['dataForm'].resetFields()
if (this.dataForm.id) {
storageBoxDetail(this.dataForm.id).then(res => {
this.dataForm = res.data
})
} else {
storageBoxCode().then(res => {
this.dataForm.code = res.data
})
}
})
},
// 表单提交
dataFormSubmit() {
this.$refs['dataForm'].validate((valid) => {
if (valid) {
const data = this.dataForm
data.id = this.dataForm.id
if (this.dataForm.id) {
storageBoxUpdate(data).then(res => {
this.$message({
message: this.$t('module.basicData.visual.success'),
type: 'success',
duration: 1500,
onClose: () => {
this.visible = false
this.$emit('refreshDataList')
}
})
})
} else {
storageBoxAdd(data).then(res => {
this.$message({
message: this.$t('module.basicData.visual.success'),
type: 'success',
duration: 1500,
onClose: () => {
this.visible = false
this.$emit('refreshDataList')
}
})
})
}
}
})
}
}
}
</script>

View File

@@ -0,0 +1,135 @@
<template>
<!--
[] 仅看可用 功能
最大30条数据
不足10条只显示一张表居中
不足20条只显示2张表居中
多张表之间有竖线分隔
每一行hover有颜色加深
每一行hover有tips出现
每一行点击时
[有颜色效果]
关闭弹窗
将选中的库位信息传递出去 { id, name }外面用对象接收展示用name发送到后端用id
-->
<div>
<el-row class="tables">
<!-- tables -->
<el-col :span="entires > 20 ? 8 : entires > 10 ? 12 : 24" class="col-1">
<simple-table :table-data="stockTable1" @stock-selected="handleStockSelect" />
</el-col>
<el-col v-if="entires > 10" :span="entires > 20 ? 8 : 12" class="col-2">
<simple-table :table-data="stockTable2" @stock-selected="handleStockSelect" />
</el-col>
<el-col v-if="entires > 20" :span="8" class="col-3">
<simple-table :table-data="stockTable3" @stock-selected="handleStockSelect" />
</el-col>
</el-row>
</div>
</template>
<script>
import SimpleTable from './simple-table.vue'
export default {
components: { SimpleTable },
props: {
stockList: { type: Array, default: () => [] },
total: { type: Number, default: 0 }
},
data() {
return {
index: 0,
stockTable1: [],
stockTable2: [],
stockTable3: []
}
},
computed: {
entires() {
return this.stockList.length
}
},
watch: {
stockList: function(val) {
this.shunt()
}
},
mounted() {
this.shunt()
},
methods: {
// 30条数据分流
shunt() {
this.index = 1 // 默认为 1
this.stockTable1.splice(0)
this.stockTable2.splice(0)
this.stockTable3.splice(0)
// 将stockList分流到stockTable 1~3
const length = this.stockList.length
if (length < 10) {
this.stockTable1 = this.stockList
.slice(0, this.stockList.length)
.map(stock => ({ ...stock, _index: this.index++ }))
} else if (length < 20) {
this.stockTable1 = this.stockList.slice(0, 10).map(stock => ({ ...stock, _index: this.index++ }))
this.stockTable2 = this.stockList
.slice(10, this.stockList.length)
.map(stock => ({ ...stock, _index: this.index++ }))
} else {
this.stockTable1 = this.stockList.slice(0, 10).map(stock => ({ ...stock, _index: this.index++ }))
this.stockTable2 = this.stockList.slice(10, 20).map(stock => ({ ...stock, _index: this.index++ }))
this.stockTable3 = this.stockList
.slice(20, this.stockList.length)
.map(stock => ({ ...stock, _index: this.index++ }))
}
// console.log('stock table 1', this.stockTable1)
// console.log('stock table 2', this.stockTable2)
// console.log('stock table 3', this.stockTable3)
},
// 处理选中事件
handleStockSelect(data) {
this.$emit('stock-selected', data)
}
}
}
</script>
<style scoped>
.tables >>> .el-table {
font-size: 12px;
}
.tables >>> .el-col + .el-col {
padding-left: 8px;
}
/* .tables >>> .col-1,
.tables >>> .col-2 {
padding-right: 8px;
border-right: 1px solid #e9e9e9;
} */
/* .tables >>> .el-col:not(:last-child) {
padding-right: 8px;
border-right: 1px solid #e9e9e9;
} */
.tables >>> .el-col:not(:first-child) {
position: relative;
}
.tables >>> .el-col:not(:first-child)::before {
content: '';
display: inline-block;
position: absolute;
top: 0;
left: 4px;
height: 100%;
width: 1px;
background: #e9e9e9;
}
</style>

View File

@@ -0,0 +1,39 @@
<!--
* @Author: lb
* @Date: 2022-3-8 10:00:00
* @LastEditors: lb
* @LastEditTime: 2022-3-17 14:38:00
* @Description: 库位详情按钮
-->
<template>
<span>
<el-button type="text" size="small" @click="emitClick">{{ $t('module.basicData.cache.ViewDetail') }}</el-button>
</span>
</template>
<script>
export default {
props: {
injectData: {
type: Object,
default: () => ({})
}
},
data() {
return {
detailType: '' // 'cache' or 'area' or 'stock' itself
}
},
mounted() {
this.detailType = this.injectData.detailType
},
methods: {
emitClick() {
// action: { 'showStocks', 'toggleEnabled' }
// data: { object }
// 通知外面,点击了库位详情按钮
this.$emit('emitData', { action: 'showStocks', data: { id: this.injectData.id }})
}
}
}
</script>

View File

@@ -0,0 +1,194 @@
<!--
* @Author: lb
* @Date: 2022-03-23 10:09:59
* @LastEditors: lb
* @LastEditTime: 2022-03-23 10:09:59
* @Description: 库存统计
-->
<template>
<div class="app-container">
<head-form :form-config="headFormConfig" @headBtnClick="btnClick" />
<base-table
:page="listQuery.current"
:limit="listQuery.size"
:table-config="tableProps"
:table-data="tableData"
:is-loading="listLoading"
/>
<pagination
v-show="total > 0"
:total="total"
:page.sync="listQuery.current"
:limit.sync="listQuery.size"
@pagination="getList"
/>
</div>
</template>
<script>
import i18n from '@/lang'
import HeadForm from '@/components/basicData/HeadForm'
import { list, getCaches } from '@/api/basicData/Cache/inventory'
import BaseTable from '@/components/BaseTable'
import Pagination from '@/components/Pagination' // Secondary package based on el-pagination
import { timeFormatter } from '@/filters'
/**
* 表格表头配置项 TypeScript接口注释
* tableConfig<ConfigItem> = []
*
* Interface ConfigItem = {
* prop: string,
* label: string,
* width: string,
* align: string,
* subcomponent: function,
* filter: function
* }
*/
const tableProps = [
{
prop: 'stockTime',
label: i18n.t('module.basicData.cache.StockTime'),
filter: timeFormatter
},
{
prop: 'cacheName',
label: i18n.t('module.basicData.cache.CacheNameAbbr')
},
{
prop: 'areaName',
label: i18n.t('module.basicData.cache.AreaNameInTable')
},
{
prop: 'stockName',
label: i18n.t('module.basicData.cache.LocationNameAbbr')
},
{
prop: 'shelfCode',
label: i18n.t('module.basicData.cache.ShelfCode')
},
{
prop: 'productName',
label: i18n.t('module.basicData.cache.ProductName')
},
{
prop: 'num',
label: i18n.t('module.basicData.cache.Quantity')
},
{
prop: 'specifications',
label: i18n.t('module.basicData.cache.Specifications')
}
]
export default {
name: 'Inventory',
components: { HeadForm, Pagination, BaseTable },
filters: {
statusFilter(status) {
const statusMap = {
published: 'success',
draft: 'info',
deleted: 'danger'
}
return statusMap[status]
}
},
data() {
return {
cacheOptions: [],
currentCache: null,
tableProps,
tableData: [],
total: 0,
listLoading: true,
listQuery: {
current: 1,
size: 20
},
CACHE_MAX_SIZE: 100,
headFormConfig: [
{
type: 'select',
label: this.$t('module.basicData.cache.CacheNameAbbr'),
selectOptions: [],
param: 'currentCache',
defaultSelect: ''
},
{
type: 'button',
btnName: 'btn.search',
name: 'search',
color: 'primary'
}
],
headFormValue: {}
}
},
created() {
this.getCacheOptions()
},
methods: {
getCacheOptions() {
// 清空一下 cacheOptions []
this.cacheOptions.splice(0, this.cacheOptions.length)
// 填充 cacheOptions
getCaches({
current: 1,
size: 100 // 这个值具体怎么处理以后肯定会改进
})
.then(response => {
response.data.records.forEach((obj, idx) => {
// 只需要cache的这两个字段
this.cacheOptions.push({ id: obj.id, name: obj.name })
this.headFormConfig[0].selectOptions = this.cacheOptions
if (idx === 0) {
// 保存第一个Cache的id为默认展示的值
this.currentCache = obj.id
this.headFormConfig[0].defaultSelect = this.currentCache
}
})
})
.then(() => {
// 待 cacheOptions 填充完并有一个默认的 cacheId 后,请求库存列表
return this.getList()
})
},
getList() {
this.listLoading = true
// 将 cacheId 作为请求参数之一传给 list()
// 请求与该缓存区对应的库存详情
list({
...this.listQuery,
cacheId: this.headFormConfig[0].defaultSelect
}).then(response => {
if (response.data.records) {
// 如果后台有数据则填充
this.tableData = response.data.records
} else {
// 如果后台无数据则清空tableData防止报错
this.tableData.splice(0, this.tableData.length)
}
this.total = response.data.total
this.listLoading = false
})
},
// 关闭弹窗
handleClosed() {
this.addOrUpdateVisible = false
},
btnClick(val) {
this.headFormValue = val
// 如果点击的是搜索栏的其他按钮在这里继续写判断
if (this.headFormValue.btnName === 'search') {
this.getList()
}
}
}
}
</script>

View File

@@ -0,0 +1,275 @@
<!--
* @Author: zwq
* @Date: 2020-12-29 15:41:11
* @LastEditors: gtz
* @LastEditTime: 2022-07-25 10:29:33
* @Description:
-->
<template>
<div class="app-container">
<head-form :form-config="headFormConfig" @headBtnClick="btnClick" />
<base-table
:top-btn-config="topBtnConfig"
:page="listQuery.current"
:limit="listQuery.size"
:table-config="tableProps"
:table-data="shelfList"
:is-loading="listLoading"
@emitFun="updateStatus"
@clickTopBtn="clickTopBtn"
>
<method-btn
slot="handleBtn"
:width="calculateWidth"
:method-list="tableBtn"
@clickBtn="handleClick"
/>
</base-table>
<pagination
v-show="total > 0"
:total="total"
:page.sync="listQuery.current"
:limit.sync="listQuery.size"
@pagination="getList()"
/>
<shelfAttr-add
v-if="addOrUpdateVisible"
ref="addOrUpdate"
:cache-id="listQuery.cacheId"
@refreshDataList="getList"
@statusChanged="updateStatus"
/>
</div>
</template>
<script>
import i18n from '@/lang'
import HeadForm from '@/components/basicData/HeadForm'
import BaseTable from '@/components/BaseTable'
import Pagination from '@/components/Pagination' // Secondary package based on el-pagination
import MethodBtn from '@/components/BaseTable/subcomponents/MethodBtn'
import { list, del, toggleEnabled } from '@/api/basicData/Cache/shelf'
import shelfAttrAdd from './components/shelfAttr-add.vue'
import statusSwitch from './components/statusBtn.vue'
/**
* 表格表头配置项 TypeScript接口注释
* tableConfig<ConfigItem> = []
*
* Interface ConfigItem = {
* prop: string,
* label: string,
* width: string,
* align: string,
* subcomponent: function,
* filter: function
* }
*
*
*/
const topBtnConfig = [
{
type: 'add',
btnName: 'btn.add'
}
]
const tableBtn = [
{
type: 'edit',
btnName: 'btn.edit'
},
{
type: 'delete',
btnName: 'btn.delete'
}
]
const tableProps = [
{
prop: 'type',
label: i18n.t('module.basicData.cache.ShelfType')
},
{
prop: 'name',
label: i18n.t('module.basicData.cache.ShelfName')
},
{
prop: 'code',
label: i18n.t('module.basicData.cache.ShelfCode')
},
{
prop: 'enabled',
label: i18n.t('module.basicData.cache.ShelfAvailable'),
subcomponent: statusSwitch
},
{
prop: 'remark',
label: i18n.t('module.basicData.cache.Notes')
}
]
export default {
name: 'Area',
components: { Pagination, BaseTable, MethodBtn, HeadForm, shelfAttrAdd },
filters: {
statusFilter(status) {
const statusMap = {
published: 'success',
draft: 'info',
deleted: 'danger'
}
return statusMap[status]
}
},
data() {
return {
topBtnConfig,
addOrUpdateVisible: false,
tableBtn,
trueWidth: 200,
tableProps,
shelfList: [],
areaList: [],
total: 0,
listLoading: true,
listQuery: {
current: 1,
size: 20
},
headFormConfig: [
{
type: 'input',
label: i18n.t('module.basicData.cache.Keywords'),
placeholder: this.$t('module.basicData.cache.ShelfName'),
param: 'keyName'
},
{
type: 'button',
btnName: 'btn.search',
name: 'search',
color: 'primary'
}
],
headFormValue: {}
}
},
computed: {
calculateWidth() {
return this.tableBtn.length * 40 // 操作列的每个按钮宽度40
}
},
created() {
// getAreaList(params).then(response => {
// if (response.data.records) {
// this.areaList = response.data.records
// }
// this.getList()
// })
this.getList()
},
methods: {
// 更新可用状态
// 货架没有'查看详情'的需求故此处不用commonEventHandler了
updateStatus({ data: vShelf }) {
toggleEnabled(vShelf).then(response => {
this.$message({
message: this.$t('module.basicData.visual.success'),
type: 'success',
duration: 1500,
onClose: () => {
this.getList()
}
})
})
},
handleClick(raw) {
if (raw.type === 'delete') {
this.$confirm(
`${this.$t('module.basicData.visual.TipsBefore')}[${raw.data.name}]?`,
this.$t('module.basicData.visual.Tips'),
{
confirmButtonText: this.$t('module.basicData.visual.confirmButtonText'),
cancelButtonText: this.$t('module.basicData.visual.cancelButtonText'),
type: 'warning'
}
)
.then(() => {
del(raw.data.id).then(response => {
this.$message({
message: this.$t('module.basicData.visual.success'),
type: 'success',
duration: 1500,
onClose: () => {
this.getList()
}
})
})
})
.catch(() => {})
} else if (raw.type === 'edit') {
// 编辑
this.addNew(raw.data.id)
} else {
// 新增
this.addNew(raw.data.id, true)
}
},
getList() {
this.listLoading = true
this.listQuery.name = this.headFormValue.keyName
// 先清空
this.shelfList.splice(0, this.shelfList.length)
// 再获取,避免启停状态不刷新
list(this.listQuery).then(response => {
if (response.data.records) {
this.shelfList = response.data.records
// this.shelfList.forEach(item => {
// const name = this.areaList.find(aitem => {
// if (aitem.id === item.areaId) return aitem
// })
// if (name) {
// item.areaName = name.name
// }
// })
} else {
this.shelfList.splice(0, this.shelfList.length)
}
this.total = response.data.total
this.listLoading = false
})
},
// 新增 / 修改
addNew(id) {
this.addOrUpdateVisible = true
this.$nextTick(() => {
this.$refs.addOrUpdate.init(id, true)
})
},
btnClick(val) {
this.headFormValue = val
// 如果点击的是搜索栏的其他按钮在这里继续写判断
if (this.headFormValue.btnName === 'search') {
this.getList()
}
},
clickTopBtn(val) {
if (val === 'add') {
this.addNew() // 新增
}
}
}
}
</script>
<style scoped>
.edit-input {
padding-right: 100px;
}
.cancel-btn {
position: absolute;
right: 15px;
top: 10px;
}
</style>

View File

@@ -0,0 +1,274 @@
<!--
* @Author: lb
* @Date: 2022-03-23 14:09:59
* @LastEditors: gtz
* @LastEditTime: 2022-07-25 10:29:36
* @Description: 出入库操作
-->
<template>
<div class="app-container">
<head-form :form-config="headFormConfig" @headBtnClick="btnClick" />
<base-table
:top-btn-config="topBtnConfig"
:page="listQuery.current"
:limit="listQuery.size"
:table-config="tableProps"
:table-data="tableData"
@clickTopBtn="clickTopBtn"
>
<method-btn
slot="handleBtn"
:width="calculateWidth"
:method-list="tableBtn"
@clickBtn="handleClick"
/>
</base-table>
<pagination
v-show="total > 0"
:total="total"
:page.sync="listQuery.current"
:limit.sync="listQuery.size"
@pagination="getList()"
/>
<storage-drawer
v-if="addOrUpdateVisible"
ref="addOrUpdate"
@refreshDataList="getList"
@handleClosed="handleClosed"
/>
</div>
</template>
<script>
import i18n from '@/lang'
import { list, del } from '@/api/basicData/Cache/storage'
import HeadForm from '@/components/basicData/HeadForm'
import BaseTable from '@/components/BaseTable'
import Pagination from '@/components/Pagination'
import MethodBtn from '@/components/BaseTable/subcomponents/MethodBtn'
import StorageDrawer from './components/storage-drawer.vue'
import { timeFormatter, operateTypeFilter, sourceFilter } from '@/filters'
/**
* 表格表头配置项 TypeScript接口注释
* tableConfig<ConfigItem> = []
*
* Interface ConfigItem = {
* prop: string,
* label: string,
* width: string,
* align: string,
* subcomponent: function,
* filter: function
* }
*/
const topBtnConfig = [
{
type: 'add',
btnName: 'btn.add'
}
]
const tableBtn = [
// {
// type: 'edit',
// btnName: 'btn.edit'
// },
{
type: 'delete',
btnName: 'btn.delete'
}
]
const tableProps = [
{
prop: 'stockTime',
label: i18n.t('module.basicData.cache.Time'),
filter: timeFormatter,
width: 180
},
{
prop: 'cacheName',
label: i18n.t('module.basicData.cache.CacheNameAbbr')
},
{
prop: 'areaName',
label: i18n.t('module.basicData.cache.AreaNameInTable')
},
{
prop: 'stockName',
label: i18n.t('module.basicData.cache.LocationNameAbbr')
},
{
prop: 'shelfCode',
label: i18n.t('module.basicData.cache.ShelfCode')
},
{
prop: 'operateType',
label: i18n.t('module.basicData.cache.OperateType'),
filter: operateTypeFilter
},
{
prop: 'source',
label: i18n.t('module.basicData.cache.Source'),
filter: sourceFilter
},
{
prop: 'productName',
label: i18n.t('module.basicData.cache.ProductName')
},
{
prop: 'num',
label: i18n.t('module.basicData.cache.Quantity')
},
{
prop: 'specifications',
label: i18n.t('module.basicData.cache.Specifications')
}
]
export default {
name: 'Storage',
components: { HeadForm, Pagination, BaseTable, MethodBtn, /* storageDialog, */ StorageDrawer },
data() {
return {
topBtnConfig,
shelfCode: null,
operation: null, // 默认没有选择任何方式
addOrUpdateVisible: false,
tableBtn,
trueWidth: 200,
tableProps,
tableData: [],
total: 0,
listLoading: false,
listQuery: {
current: 1,
size: 20
},
headFormConfig: [
{
type: 'input',
label: this.$t('module.basicData.cache.ShelfCode'),
placeholder: this.$t('module.basicData.cache.ShelfCode'),
param: 'shelfCode'
},
{
type: 'select',
label: this.$t('module.basicData.cache.OperateType'),
selectOptions: [
{ id: '0', name: this.$t('module.basicData.cache.All') },
{ id: '1', name: this.$t('module.basicData.cache.Export') },
{ id: '2', name: this.$t('module.basicData.cache.Import') }
],
param: 'operation'
},
{
type: 'button',
btnName: 'btn.search',
name: 'search',
color: 'primary'
}
],
headFormValue: {}
}
},
computed: {
calculateWidth() {
return this.tableBtn.length * 40 // 操作列的每个按钮宽度40
}
},
created() {
this.getList()
},
methods: {
handleClick(raw) {
if (raw.type === 'delete') {
this.$confirm(
`${this.$t('module.basicData.visual.TipsBefore')} [id为:${raw.data.id}] 的记录吗?`,
this.$t('module.basicData.visual.Tips'),
{
confirmButtonText: this.$t('module.basicData.visual.confirmButtonText'),
cancelButtonText: this.$t('module.basicData.visual.cancelButtonText'),
type: 'warning'
}
)
.then(() => {
del(raw.data.id).then(response => {
this.$message({
message: this.$t('module.basicData.visual.success'),
type: 'success',
duration: 1500,
onClose: () => {
this.getList()
}
})
})
})
.catch(() => {})
} else if (raw.type === 'edit') {
this.addNew(raw.data.id)
}
},
doNothing() {},
getList() {
this.listLoading = true
// 准备额外参数
const extraParams = {}
// 如果没有选择出库、还是入库则默认全部0 代表全部
extraParams.operateType = this.headFormValue.operation ? this.headFormValue.operation : 0
// 如果设置了 shelfCode 过滤条件,则加上
this.headFormValue.shelfCode ? (extraParams.shelfCode = this.headFormValue.shelfCode) : this.doNothing()
// 发起请求
list({
...this.listQuery,
...extraParams
}).then(response => {
if (response.data.records) {
this.tableData = response.data.records
} else {
this.tableData.splice(0, this.tableData.length)
}
this.total = response.data.total
this.listLoading = false
})
},
// 新增 / 修改
addNew(id, readonly) {
this.addOrUpdateVisible = true
this.$nextTick(() => {
this.$refs.addOrUpdate.init(id, readonly)
})
},
// 关闭弹窗
handleClosed() {
this.addOrUpdateVisible = false
},
add() {},
btnClick(val) {
this.headFormValue = val
// 如果点击的是搜索栏的其他按钮在这里继续写判断
if (this.headFormValue.btnName === 'search') {
this.getList()
}
},
clickTopBtn(val) {
if (val === 'add') {
this.addNew() // 新增
}
}
}
}
</script>
<style scoped>
.edit-input {
padding-right: 100px;
}
.cancel-btn {
position: absolute;
right: 15px;
top: 10px;
}
</style>

View File

@@ -0,0 +1,223 @@
<!--
* @Author: zwq
* @Date: 2020-12-29 15:41:11
* @LastEditors: gtz
* @LastEditTime: 2022-07-25 10:29:39
* @Description:
-->
<template>
<div class="app-container">
<head-form :placeholder-name="placeholderName" :key-name="keyName" @getDataList="getList" @add="addNew" />
<base-table
:page="listQuery.current"
:limit="listQuery.size"
:table-config="tableProps"
:table-data="list"
:is-loading="listLoading"
>
<method-btn
slot="handleBtn"
:width="calculateWidth"
:method-list="tableBtn"
@clickBtn="handleClick"
/>
</base-table>
<pagination
v-show="total > 0"
:total="total"
:page.sync="listQuery.current"
:limit.sync="listQuery.size"
@pagination="getList()"
/>
<storageBox-add
v-if="addOrUpdateVisible"
ref="addOrUpdate"
:cache-id="listQuery.cacheId"
@refreshDataList="getList"
/>
</div>
</template>
<script>
import i18n from '@/lang'
import HeadForm from '@/components/basicData/HeadForm'
import BaseTable from '@/components/BaseTable'
import PositionDetail from './components/PositionDetail'
import storageBoxAdd from './components/storageBox-add'
import Pagination from '@/components/Pagination' // Secondary package based on el-pagination
import MethodBtn from '@/components/BaseTable/subcomponents/MethodBtn'
import { storageBoxList, storageBoxDelete } from '@/api/basicData/Cache/storageBox'
import { timeFormatter } from '@/filters'
import basicData from '@/filters/basicData'
/**
* 表格表头配置项 TypeScript接口注释
* tableConfig<ConfigItem> = []
*
* Interface ConfigItem = {
* prop: string,
* label: string,
* width: string,
* align: string,
* subcomponent: function,
* filter: function
* }
*
*
*/
const tableBtn = [
{
type: 'edit',
btnName: 'btn.edit'
},
{
type: 'delete',
btnName: 'btn.delete'
}
]
const tableProps = [
{
prop: 'createTime',
label: i18n.t('module.basicData.factory.createTime'),
filter: timeFormatter
},
{
prop: 'name',
label: i18n.t('module.basicData.storageBox.name')
},
{
prop: 'code',
label: i18n.t('module.basicData.storageBox.code')
},
{
prop: 'aliasName',
label: i18n.t('module.basicData.storageBox.alias')
},
{
prop: 'quantity',
label: i18n.t('module.basicData.storageBox.StorageQuantity')
},
{
prop: 'status',
label: i18n.t('module.basicData.storageBox.status'),
filter: basicData('storage')
},
{
prop: 'remark',
label: i18n.t('module.basicData.storageBox.remark')
},
{
prop: 'location',
label: i18n.t('module.basicData.cache.Location'),
subcomponent: PositionDetail
}
]
export default {
name: 'Area',
components: { Pagination, BaseTable, MethodBtn, HeadForm, storageBoxAdd },
filters: {
statusFilter(status) {
const statusMap = {
published: 'success',
draft: 'info',
deleted: 'danger'
}
return statusMap[status]
}
},
data() {
return {
addOrUpdateVisible: false,
keyName: i18n.t('module.basicData.visual.keyword'),
placeholderName:
this.$t('module.basicData.storageBox.name') +
this.$t('module.basicData.visual.Or') +
this.$t('module.basicData.storageBox.code'),
tableBtn,
trueWidth: 200,
tableProps,
list: [],
areaList: [],
total: 0,
listLoading: true,
listQuery: {
current: 1,
size: 10
}
}
},
computed: {
calculateWidth() {
return this.tableBtn.length * 40 // 操作列的每个按钮宽度40
}
},
created() {
this.getList()
},
methods: {
handleClick(raw) {
if (raw.type === 'delete') {
this.$confirm(
`${this.$t('module.basicData.visual.TipsBefore')}[${raw.data.name}]?`,
this.$t('module.basicData.visual.Tips'),
{
confirmButtonText: this.$t('module.basicData.visual.confirmButtonText'),
cancelButtonText: this.$t('module.basicData.visual.cancelButtonText'),
type: 'warning'
}
)
.then(() => {
storageBoxDelete(raw.data.id).then(response => {
this.$message({
message: this.$t('module.basicData.visual.success'),
type: 'success',
duration: 1500,
onClose: () => {
this.getList()
}
})
})
})
.catch(() => {})
} else if (raw.type === 'edit') {
this.addNew(raw.data.id)
} else {
this.addNew(raw.data.id, true)
}
},
getList(key) {
this.listLoading = true
this.listQuery.name = key
this.listQuery.code = key
storageBoxList(this.listQuery).then(response => {
if (response.data.records) {
this.list = response.data.records
} else {
this.list.splice(0, this.list.length)
}
this.total = response.data.total
this.listLoading = false
})
},
// 新增 / 修改
addNew(id) {
this.addOrUpdateVisible = true
this.$nextTick(() => {
this.$refs.addOrUpdate.init(id, true)
})
}
}
}
</script>
<style scoped>
.edit-input {
padding-right: 100px;
}
.cancel-btn {
position: absolute;
right: 15px;
top: 10px;
}
</style>