Compare commits
2 Commits
72c1684f30
...
c2411d623b
| Author | SHA1 | Date | |
|---|---|---|---|
| c2411d623b | |||
| 3ce7eaf284 |
@@ -97,6 +97,9 @@ const mainRoutes = {
|
|||||||
{ path: '/statisticsBusiness-courseStatistics', component: _import('modules/statisticsBusiness/courseStatistics/index'), name: 'statisticsBusiness-courseStatistics', meta: { title: '课程统计', isTab: true } },
|
{ path: '/statisticsBusiness-courseStatistics', component: _import('modules/statisticsBusiness/courseStatistics/index'), name: 'statisticsBusiness-courseStatistics', meta: { title: '课程统计', isTab: true } },
|
||||||
{ path: '/statisticsBusiness-vipStatistics', component: _import('modules/statisticsBusiness/vipStatistics/index'), name: 'statisticsBusiness-vipStatistics', meta: { title: 'VIP统计', isTab: true } },
|
{ path: '/statisticsBusiness-vipStatistics', component: _import('modules/statisticsBusiness/vipStatistics/index'), name: 'statisticsBusiness-vipStatistics', meta: { title: 'VIP统计', isTab: true } },
|
||||||
{ path: '/statisticsBusiness-userStatistics', component: _import('modules/statisticsBusiness/userStatistics/index'), name: 'statisticsBusiness-userStatistics', meta: { title: '用户统计', isTab: true } },
|
{ path: '/statisticsBusiness-userStatistics', component: _import('modules/statisticsBusiness/userStatistics/index'), name: 'statisticsBusiness-userStatistics', meta: { title: '用户统计', isTab: true } },
|
||||||
|
{ path: '/inventoryManagement-stockInRecord', component: _import('modules/inventoryManagement/stockInRecord'), name: 'inventoryManagement-stockInRecord', meta: { title: '入库记录', isTab: true } },
|
||||||
|
{ path: '/inventoryManagement-stockOutRecord', component: _import('modules/inventoryManagement/stockOutRecord'), name: 'inventoryManagement-stockOutRecord', meta: { title: '出库记录', isTab: true } },
|
||||||
|
{ path: '/inventoryManagement-inventoryManage', component: _import('modules/inventoryManagement/inventoryManage'), name: 'inventoryManagement-inventoryManage', meta: { title: '库存管理', isTab: true } },
|
||||||
],
|
],
|
||||||
beforeEnter (to, from, next) {
|
beforeEnter (to, from, next) {
|
||||||
let token = Vue.cookie.get('token')
|
let token = Vue.cookie.get('token')
|
||||||
|
|||||||
@@ -21,6 +21,17 @@
|
|||||||
</el-card>
|
</el-card>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
<el-row :gutter="12" style="margin-top: 30px;">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-card shadow="hover">
|
||||||
|
库存预警
|
||||||
|
<span class="number">{{ stockAlertNum }}</span>
|
||||||
|
<router-link :to="{ name: 'inventoryManagement-inventoryManage', query: { isAlert: 1 } }">
|
||||||
|
<el-button type="primary" size="mini">去处理</el-button>
|
||||||
|
</router-link>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
<el-row :gutter="12" style="margin-top: 30px;" v-if="medicalNum > 0||medicalNum2>0">
|
<el-row :gutter="12" style="margin-top: 30px;" v-if="medicalNum > 0||medicalNum2>0">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover">
|
||||||
@@ -50,6 +61,7 @@ export default {
|
|||||||
medicalNum2: 0,
|
medicalNum2: 0,
|
||||||
orderNum: 0,
|
orderNum: 0,
|
||||||
workOrderNum: 0,
|
workOrderNum: 0,
|
||||||
|
stockAlertNum: 0,
|
||||||
// loadAll:true,
|
// loadAll:true,
|
||||||
loaded: 0
|
loaded: 0
|
||||||
};
|
};
|
||||||
@@ -58,6 +70,7 @@ export default {
|
|||||||
this.getMedicalList();
|
this.getMedicalList();
|
||||||
this.getDataList();
|
this.getDataList();
|
||||||
this.getWorkDataList();
|
this.getWorkDataList();
|
||||||
|
this.getStockAlertCount();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// 待发出列表
|
// 待发出列表
|
||||||
@@ -140,12 +153,38 @@ export default {
|
|||||||
}).then(({ data }) => {
|
}).then(({ data }) => {
|
||||||
this.medicalNum2 = data.page.total;
|
this.medicalNum2 = data.page.total;
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
getStockAlertCount() {
|
||||||
|
Promise.all([1, 2].map(merchantId =>
|
||||||
|
this.$http.request({
|
||||||
|
url: this.$http.adornUrl('/master/inventoryManagement/stockStatistics'),
|
||||||
|
method: 'POST',
|
||||||
|
data: {
|
||||||
|
merchantId,
|
||||||
|
current: 1,
|
||||||
|
limit: 1,
|
||||||
|
isAlert: 1
|
||||||
|
},
|
||||||
|
header: { 'Content-Type': 'application/json' }
|
||||||
|
})
|
||||||
|
)).then(results => {
|
||||||
|
this.stockAlertNum = results.reduce((sum, { data }) => {
|
||||||
|
if (data && data.code === 0) {
|
||||||
|
return sum + (data.result.total || 0)
|
||||||
|
}
|
||||||
|
return sum
|
||||||
|
}, 0)
|
||||||
|
this.loaded += 1
|
||||||
|
}).catch(() => {
|
||||||
|
this.$message.error('获取库存预警数量失败')
|
||||||
|
this.loaded += 1
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
loadAll() {
|
loadAll() {
|
||||||
console.log("this.loaded", this.loaded);
|
console.log("this.loaded", this.loaded);
|
||||||
if (this.loaded == 2) {
|
if (this.loaded == 3) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -241,17 +241,24 @@ export default {
|
|||||||
'content': content
|
'content': content
|
||||||
})
|
})
|
||||||
}).then(res => {
|
}).then(res => {
|
||||||
this.$message({
|
if (data && data.code === 0) {
|
||||||
message: '成功',
|
this.$message({
|
||||||
type: 'success'
|
message: '成功',
|
||||||
})
|
type: 'success'
|
||||||
|
})
|
||||||
|
this.loading = false
|
||||||
|
this.dataForm.voices = res.data.voices
|
||||||
|
var voices = { name: '音频文件', url: res.data.voices }
|
||||||
|
var attr = []
|
||||||
|
attr.push(voices)
|
||||||
|
this.fileListVoices = attr
|
||||||
|
console.log(res)
|
||||||
|
} else {
|
||||||
|
this.$message.error(res.msg)
|
||||||
|
}
|
||||||
|
}).catch(() => {
|
||||||
this.loading = false
|
this.loading = false
|
||||||
this.dataForm.voices = res.data.voices
|
this.$message.error('请求失败')
|
||||||
var voices = { name: '音频文件', url: res.data.voices }
|
|
||||||
var attr = []
|
|
||||||
attr.push(voices)
|
|
||||||
this.fileListVoices = attr
|
|
||||||
console.log(res)
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
// 富文本内容赋值
|
// 富文本内容赋值
|
||||||
|
|||||||
@@ -0,0 +1,183 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
v-if="visible"
|
||||||
|
title="批量出库"
|
||||||
|
:visible.sync="visible"
|
||||||
|
width="520px"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
:close-on-press-escape="!submitting"
|
||||||
|
:show-close="!submitting"
|
||||||
|
@closed="handleClosed"
|
||||||
|
>
|
||||||
|
<div v-loading="submitting" element-loading-text="提交中...">
|
||||||
|
<el-form
|
||||||
|
ref="form"
|
||||||
|
:model="form"
|
||||||
|
:rules="formRules"
|
||||||
|
label-width="120px"
|
||||||
|
>
|
||||||
|
<el-form-item label="出库类型" prop="outboundType">
|
||||||
|
<el-select
|
||||||
|
v-model="form.outboundType"
|
||||||
|
placeholder="请选择出库类型"
|
||||||
|
style="width: 100%"
|
||||||
|
clearable
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in outboundTypeOptions"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="文件" prop="file">
|
||||||
|
<el-upload
|
||||||
|
ref="upload"
|
||||||
|
action="#"
|
||||||
|
:auto-upload="false"
|
||||||
|
:limit="1"
|
||||||
|
accept=".xlsx,.xls"
|
||||||
|
:file-list="fileList"
|
||||||
|
:on-change="handleFileChange"
|
||||||
|
:on-remove="handleFileRemove"
|
||||||
|
:on-exceed="handleExceed"
|
||||||
|
>
|
||||||
|
<el-button size="small" type="primary">选择文件</el-button>
|
||||||
|
</el-upload>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<span slot="footer">
|
||||||
|
<el-button :disabled="submitting" @click="visible = false">取消</el-button>
|
||||||
|
<el-button type="primary" :loading="submitting" @click="handleSubmit">确定</el-button>
|
||||||
|
</span>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const EXCLUDED_OUTBOUND_TYPES = ['App', 'donation']
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'BatchOutboundDialog',
|
||||||
|
data() {
|
||||||
|
const validateFile = (rule, value, callback) => {
|
||||||
|
if (!this.form.file) {
|
||||||
|
callback(new Error('请选择文件'))
|
||||||
|
} else {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
visible: false,
|
||||||
|
submitting: false,
|
||||||
|
merchantId: 1,
|
||||||
|
outboundTypeOptions: [],
|
||||||
|
fileList: [],
|
||||||
|
form: {
|
||||||
|
outboundType: '',
|
||||||
|
file: null
|
||||||
|
},
|
||||||
|
formRules: {
|
||||||
|
outboundType: [{ required: true, message: '请选择出库类型', trigger: 'change' }],
|
||||||
|
file: [{ required: true, validator: validateFile, trigger: 'change' }]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getOutboundTypeOptions() {
|
||||||
|
return this.$http({
|
||||||
|
url: this.$http.adornUrl('/book/sysdictdata/selectByType/inventory_outbound_type'),
|
||||||
|
method: 'get'
|
||||||
|
}).then(({ data }) => {
|
||||||
|
const list = (data && data.dataList) || []
|
||||||
|
this.outboundTypeOptions = list
|
||||||
|
.filter(item => !EXCLUDED_OUTBOUND_TYPES.includes(item.dictType))
|
||||||
|
.map(item => ({
|
||||||
|
label: item.dictValue,
|
||||||
|
value: item.dictType
|
||||||
|
}))
|
||||||
|
}).catch(() => {
|
||||||
|
this.outboundTypeOptions = []
|
||||||
|
})
|
||||||
|
},
|
||||||
|
open(merchantId) {
|
||||||
|
this.merchantId = Number(merchantId)
|
||||||
|
this.submitting = false
|
||||||
|
this.getOutboundTypeOptions().finally(() => {
|
||||||
|
this.resetForm()
|
||||||
|
this.visible = true
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (this.$refs.form) {
|
||||||
|
this.$refs.form.clearValidate()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
resetForm() {
|
||||||
|
this.form = {
|
||||||
|
outboundType: '',
|
||||||
|
file: null
|
||||||
|
}
|
||||||
|
this.fileList = []
|
||||||
|
if (this.$refs.upload) {
|
||||||
|
this.$refs.upload.clearFiles()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleFileChange(file, fileList) {
|
||||||
|
this.fileList = fileList.slice(-1)
|
||||||
|
this.form.file = file.raw || null
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (this.$refs.form) {
|
||||||
|
this.$refs.form.validateField('file')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleFileRemove() {
|
||||||
|
this.fileList = []
|
||||||
|
this.form.file = null
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (this.$refs.form) {
|
||||||
|
this.$refs.form.validateField('file')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleExceed() {
|
||||||
|
this.$message.warning('只能上传一个文件')
|
||||||
|
},
|
||||||
|
handleSubmit() {
|
||||||
|
this.$refs.form.validate(valid => {
|
||||||
|
if (!valid) return
|
||||||
|
this.submitting = true
|
||||||
|
const formData = new FormData()
|
||||||
|
formData.append('file', this.form.file)
|
||||||
|
formData.append('outboundType', this.form.outboundType)
|
||||||
|
formData.append('merchantId', this.merchantId)
|
||||||
|
this.$http({
|
||||||
|
url: this.$http.adornUrl('/master/inventoryManagement/batchOutbound'),
|
||||||
|
method: 'post',
|
||||||
|
data: formData,
|
||||||
|
headers: { 'Content-Type': 'multipart/form-data' }
|
||||||
|
}).then(({ data }) => {
|
||||||
|
if (data && data.code === 0) {
|
||||||
|
this.$message.success('操作成功')
|
||||||
|
this.visible = false
|
||||||
|
this.$emit('success')
|
||||||
|
} else {
|
||||||
|
this.$message.error(data.msg || '操作失败')
|
||||||
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
this.$message.error('操作失败')
|
||||||
|
}).finally(() => {
|
||||||
|
this.submitting = false
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleClosed() {
|
||||||
|
this.submitting = false
|
||||||
|
this.resetForm()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
<template>
|
||||||
|
<el-select
|
||||||
|
:value="value"
|
||||||
|
filterable
|
||||||
|
remote
|
||||||
|
clearable
|
||||||
|
reserve-keyword
|
||||||
|
:placeholder="placeholder"
|
||||||
|
:remote-method="searchProducts"
|
||||||
|
:loading="loading"
|
||||||
|
:style="selectStyle"
|
||||||
|
@input="$emit('input', $event)"
|
||||||
|
@change="handleChange"
|
||||||
|
@clear="handleClear"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in options"
|
||||||
|
:key="item.productId"
|
||||||
|
:label="item.productName"
|
||||||
|
:value="item.productId"
|
||||||
|
>
|
||||||
|
<span>{{ item.productName }}</span>
|
||||||
|
<span style="color: #999; margin-left: 8px">ID:{{ item.productId }}</span>
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import debounce from 'lodash/debounce'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ProductRemoteSelect',
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
merchantId: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: '1'
|
||||||
|
},
|
||||||
|
goodsType: {
|
||||||
|
type: String,
|
||||||
|
default: '00'
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: '请输入商品名称检索'
|
||||||
|
},
|
||||||
|
selectStyle: {
|
||||||
|
type: String,
|
||||||
|
default: 'width: 240px'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
options: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
merchantId() {
|
||||||
|
this.resetSelection()
|
||||||
|
},
|
||||||
|
goodsType() {
|
||||||
|
this.resetSelection()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.debouncedSearch = debounce(this.fetchProducts, 300)
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
if (this.debouncedSearch && this.debouncedSearch.cancel) {
|
||||||
|
this.debouncedSearch.cancel()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
clear() {
|
||||||
|
if (this.debouncedSearch && this.debouncedSearch.cancel) {
|
||||||
|
this.debouncedSearch.cancel()
|
||||||
|
}
|
||||||
|
this.options = []
|
||||||
|
this.loading = false
|
||||||
|
},
|
||||||
|
resetSelection() {
|
||||||
|
this.options = []
|
||||||
|
this.$emit('input', '')
|
||||||
|
this.$emit('change', null)
|
||||||
|
},
|
||||||
|
searchProducts(query) {
|
||||||
|
if (!query) {
|
||||||
|
this.options = []
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.debouncedSearch(query)
|
||||||
|
},
|
||||||
|
fetchProducts(query) {
|
||||||
|
this.loading = true
|
||||||
|
const params = {
|
||||||
|
current: 1,
|
||||||
|
limit: 20,
|
||||||
|
goodsType: this.goodsType
|
||||||
|
}
|
||||||
|
if (query) {
|
||||||
|
params.productName = query
|
||||||
|
}
|
||||||
|
this.$http({
|
||||||
|
url: this.$http.adornUrl('/master/shopProduct/listByPage'),
|
||||||
|
method: 'post',
|
||||||
|
data: this.$http.adornData(params)
|
||||||
|
}).then(({ data }) => {
|
||||||
|
if (data && data.code === 0) {
|
||||||
|
this.options = data.result.records || []
|
||||||
|
} else {
|
||||||
|
this.options = []
|
||||||
|
}
|
||||||
|
this.loading = false
|
||||||
|
}).catch(() => {
|
||||||
|
this.options = []
|
||||||
|
this.loading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleChange(productId) {
|
||||||
|
const product = this.options.find(item => item.productId === productId) || null
|
||||||
|
this.$emit('change', product)
|
||||||
|
},
|
||||||
|
handleClear() {
|
||||||
|
this.options = []
|
||||||
|
this.$emit('change', null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,289 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
v-if="visible"
|
||||||
|
:title="dialogTitle"
|
||||||
|
:visible.sync="visible"
|
||||||
|
width="520px"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
@closed="handleClosed"
|
||||||
|
>
|
||||||
|
<el-form
|
||||||
|
ref="form"
|
||||||
|
:model="form"
|
||||||
|
:rules="formRules"
|
||||||
|
label-width="120px"
|
||||||
|
>
|
||||||
|
<el-form-item v-if="bizType === 2" label="出库类型" prop="outboundType">
|
||||||
|
<el-select
|
||||||
|
v-model="form.outboundType"
|
||||||
|
placeholder="请选择出库类型"
|
||||||
|
style="width: 100%"
|
||||||
|
clearable
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in outboundTypeOptions"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="商品类型" prop="goodsType">
|
||||||
|
<el-radio-group v-model="form.goodsType" @change="handleGoodsTypeChange">
|
||||||
|
<el-radio
|
||||||
|
v-for="item in goodsTypeOptions"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.value"
|
||||||
|
>{{ item.label }}</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="商品" prop="productId">
|
||||||
|
<product-remote-select
|
||||||
|
v-model="form.productId"
|
||||||
|
:merchant-id="merchantId"
|
||||||
|
:goods-type="form.goodsType"
|
||||||
|
placeholder="请输入商品名称检索"
|
||||||
|
select-style="width: 100%"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item v-if="bizType === 1" label="供应商类型" prop="source">
|
||||||
|
<el-select
|
||||||
|
v-model="form.source"
|
||||||
|
placeholder="请选择供应商类型"
|
||||||
|
style="width: 100%"
|
||||||
|
clearable
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in sourceOptions"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="数量" prop="quantity">
|
||||||
|
<el-input-number
|
||||||
|
v-model="form.quantity"
|
||||||
|
:min="1"
|
||||||
|
:precision="0"
|
||||||
|
controls-position="right"
|
||||||
|
style="width: 100%"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="单价" prop="unitCost">
|
||||||
|
<el-input-number
|
||||||
|
v-model="form.unitCost"
|
||||||
|
:min="0"
|
||||||
|
:precision="2"
|
||||||
|
controls-position="right"
|
||||||
|
style="width: 100%"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="备注">
|
||||||
|
<el-input
|
||||||
|
v-model="form.remark"
|
||||||
|
type="textarea"
|
||||||
|
:rows="2"
|
||||||
|
placeholder="选填"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="合计价格">
|
||||||
|
<span class="total-price">{{ totalPrice }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<span slot="footer">
|
||||||
|
<el-button @click="visible = false">取消</el-button>
|
||||||
|
<el-button type="primary" :loading="submitting" @click="handleSubmit">确定</el-button>
|
||||||
|
</span>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import ProductRemoteSelect from './productRemoteSelect.vue'
|
||||||
|
|
||||||
|
const GOODS_TYPE_LABELS = ['书籍', '预售书', '仪器']
|
||||||
|
const DEFAULT_GOODS_TYPE_OPTIONS = [
|
||||||
|
{ label: '书籍', value: '00' },
|
||||||
|
{ label: '预售书', value: '01' },
|
||||||
|
{ label: '仪器', value: '02' }
|
||||||
|
]
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'PurchaseDialog',
|
||||||
|
components: { ProductRemoteSelect },
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
visible: false,
|
||||||
|
submitting: false,
|
||||||
|
bizType: 1,
|
||||||
|
merchantId: '1',
|
||||||
|
goodsTypeOptions: DEFAULT_GOODS_TYPE_OPTIONS,
|
||||||
|
sourceOptions: [],
|
||||||
|
outboundTypeOptions: [],
|
||||||
|
form: {
|
||||||
|
goodsType: '00',
|
||||||
|
productId: '',
|
||||||
|
source: '',
|
||||||
|
outboundType: '',
|
||||||
|
quantity: 1,
|
||||||
|
unitCost: 0,
|
||||||
|
remark: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
dialogTitle() {
|
||||||
|
return this.bizType === 1 ? '入库' : '出库'
|
||||||
|
},
|
||||||
|
totalPrice() {
|
||||||
|
const qty = this.form.quantity || 0
|
||||||
|
const cost = this.form.unitCost || 0
|
||||||
|
return (qty * cost).toFixed(2)
|
||||||
|
},
|
||||||
|
formRules() {
|
||||||
|
const rules = {
|
||||||
|
goodsType: [{ required: true, message: '请选择商品类型', trigger: 'change' }],
|
||||||
|
productId: [{ required: true, message: '请选择商品', trigger: 'change' }],
|
||||||
|
quantity: [{ required: true, message: '请输入数量', trigger: 'blur' }],
|
||||||
|
unitCost: [{ required: true, message: '请输入单价', trigger: 'blur' }]
|
||||||
|
}
|
||||||
|
if (this.bizType === 1) {
|
||||||
|
rules.source = [{ required: true, message: '请选择供应商类型', trigger: 'change' }]
|
||||||
|
}
|
||||||
|
if (this.bizType === 2) {
|
||||||
|
rules.outboundType = [{ required: true, message: '请选择出库类型', trigger: 'change' }]
|
||||||
|
}
|
||||||
|
return rules
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getGoodsTypeOptions() {
|
||||||
|
return this.$http({
|
||||||
|
url: this.$http.adornUrl('/book/sysdictdata/selectByType/goodsType'),
|
||||||
|
method: 'get'
|
||||||
|
}).then(({ data }) => {
|
||||||
|
const list = (data && data.dataList) || []
|
||||||
|
const options = list
|
||||||
|
.filter(item => GOODS_TYPE_LABELS.includes(item.dictValue))
|
||||||
|
.map(item => ({ label: item.dictValue, value: item.dictType }))
|
||||||
|
if (options.length) {
|
||||||
|
this.goodsTypeOptions = options
|
||||||
|
}
|
||||||
|
}).catch(() => {})
|
||||||
|
},
|
||||||
|
getSourceTypeOptions() {
|
||||||
|
return this.$http({
|
||||||
|
url: this.$http.adornUrl('/book/sysdictdata/selectByType/inventory_source_type'),
|
||||||
|
method: 'get'
|
||||||
|
}).then(({ data }) => {
|
||||||
|
const list = (data && data.dataList) || []
|
||||||
|
this.sourceOptions = list.map(item => ({
|
||||||
|
label: item.dictValue,
|
||||||
|
value: item.dictType
|
||||||
|
}))
|
||||||
|
}).catch(() => {
|
||||||
|
this.sourceOptions = []
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getOutboundTypeOptions() {
|
||||||
|
return this.$http({
|
||||||
|
url: this.$http.adornUrl('/book/sysdictdata/selectByType/inventory_outbound_type'),
|
||||||
|
method: 'get'
|
||||||
|
}).then(({ data }) => {
|
||||||
|
const list = (data && data.dataList) || []
|
||||||
|
this.outboundTypeOptions = list.map(item => ({
|
||||||
|
label: item.dictValue,
|
||||||
|
value: item.dictType
|
||||||
|
}))
|
||||||
|
}).catch(() => {
|
||||||
|
this.outboundTypeOptions = []
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getDefaultGoodsType() {
|
||||||
|
const bookType = this.goodsTypeOptions.find(item => item.label === '书籍')
|
||||||
|
return bookType ? bookType.value : '00'
|
||||||
|
},
|
||||||
|
open(bizType, merchantId) {
|
||||||
|
this.bizType = bizType
|
||||||
|
this.merchantId = Number(merchantId)
|
||||||
|
this.submitting = false
|
||||||
|
const requests = [this.getGoodsTypeOptions()]
|
||||||
|
if (bizType === 1) {
|
||||||
|
requests.push(this.getSourceTypeOptions())
|
||||||
|
} else {
|
||||||
|
requests.push(this.getOutboundTypeOptions())
|
||||||
|
}
|
||||||
|
Promise.all(requests).finally(() => {
|
||||||
|
this.form = {
|
||||||
|
goodsType: this.getDefaultGoodsType(),
|
||||||
|
productId: '',
|
||||||
|
source: '',
|
||||||
|
outboundType: '',
|
||||||
|
quantity: 1,
|
||||||
|
unitCost: 0,
|
||||||
|
remark: ''
|
||||||
|
}
|
||||||
|
this.visible = true
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (this.$refs.form) {
|
||||||
|
this.$refs.form.clearValidate()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleGoodsTypeChange() {
|
||||||
|
this.form.productId = ''
|
||||||
|
},
|
||||||
|
handleSubmit() {
|
||||||
|
this.$refs.form.validate(valid => {
|
||||||
|
if (!valid) return
|
||||||
|
this.submitting = true
|
||||||
|
const payload = {
|
||||||
|
productId: this.form.productId,
|
||||||
|
merchantId: this.merchantId,
|
||||||
|
quantity: this.form.quantity,
|
||||||
|
unitCost: this.form.unitCost,
|
||||||
|
biz_type: this.bizType
|
||||||
|
}
|
||||||
|
if (this.form.remark) {
|
||||||
|
payload.remark = this.form.remark
|
||||||
|
}
|
||||||
|
if (this.bizType === 1) {
|
||||||
|
payload.source = this.form.source
|
||||||
|
}
|
||||||
|
if (this.bizType === 2) {
|
||||||
|
payload.outboundType = this.form.outboundType
|
||||||
|
}
|
||||||
|
this.$http({
|
||||||
|
url: this.$http.adornUrl('/master/inventoryManagement/purchaseProduct'),
|
||||||
|
method: 'post',
|
||||||
|
data: this.$http.adornData(payload)
|
||||||
|
}).then(({ data }) => {
|
||||||
|
this.submitting = false
|
||||||
|
if (data && data.code === 0) {
|
||||||
|
this.$message.success('操作成功')
|
||||||
|
this.visible = false
|
||||||
|
this.$emit('success')
|
||||||
|
} else {
|
||||||
|
this.$message.error(data.msg || '操作失败')
|
||||||
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
this.submitting = false
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleClosed() {
|
||||||
|
this.submitting = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.total-price {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #17b3a3;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,227 @@
|
|||||||
|
<template>
|
||||||
|
<div class="mod-config">
|
||||||
|
<el-tabs v-model="merchantId" type="card" @tab-click="changeTab">
|
||||||
|
<el-tab-pane label="众妙之门" name="2" />
|
||||||
|
<el-tab-pane label="灵枢教育科技" name="1" />
|
||||||
|
</el-tabs>
|
||||||
|
|
||||||
|
<el-form
|
||||||
|
:inline="true"
|
||||||
|
:model="dataForm"
|
||||||
|
@keyup.enter.native="handleSearch"
|
||||||
|
>
|
||||||
|
<el-form-item>
|
||||||
|
<el-input
|
||||||
|
v-model="dataForm.productName"
|
||||||
|
placeholder="商品名称"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-date-picker
|
||||||
|
v-model="dataForm.dateRange"
|
||||||
|
type="daterange"
|
||||||
|
value-format="yyyy-MM-dd"
|
||||||
|
range-separator="至"
|
||||||
|
start-placeholder="开始日期"
|
||||||
|
end-placeholder="结束日期"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button @click="handleSearch">查询</el-button>
|
||||||
|
<el-button type="success" :loading="exportLoading" @click="handleExport">导出</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<!-- <div v-if="remainTotalStock !== null" class="summary-bar">
|
||||||
|
库存合计:<span class="summary-value">{{ remainTotalStock }}</span>
|
||||||
|
</div> -->
|
||||||
|
|
||||||
|
<el-table
|
||||||
|
:data="dataList"
|
||||||
|
border
|
||||||
|
v-loading="dataListLoading"
|
||||||
|
height="65vh"
|
||||||
|
style="width: 100%"
|
||||||
|
>
|
||||||
|
<el-table-column prop="id" label="ID" width="70" align="center" />
|
||||||
|
<el-table-column prop="productId" label="商品ID" width="90" align="center" />
|
||||||
|
<el-table-column prop="productName" label="商品名称" align="center" min-width="160" />
|
||||||
|
<el-table-column prop="quantity" :label="quantityLabel" width="100" align="center" />
|
||||||
|
<el-table-column v-if="bizType === 1" prop="remainQuantity" label="剩余数量" width="100" align="center" />
|
||||||
|
<el-table-column prop="unitCost" label="成本单价" width="100" align="center" />
|
||||||
|
<el-table-column label="时间" width="170" align="center">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
{{ formatTime(scope.row.create_time) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column v-if="bizType === 1" label="供应商类型" width="100" align="center">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
{{ formatSource(scope.row.source) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column v-if="bizType === 2" prop="outboundTypeLabel" label="出库类型" width="100" align="center" />
|
||||||
|
<el-table-column label="备注" align="center" min-width="120">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
{{ scope.row.remark || '-' }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column v-if="bizType === 2" label="订单号" width="200" align="center">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
{{ scope.row.orderSn != null ? scope.row.orderSn : '-' }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<el-pagination
|
||||||
|
@size-change="sizeChangeHandle"
|
||||||
|
@current-change="currentChangeHandle"
|
||||||
|
:current-page="pageIndex"
|
||||||
|
:page-sizes="[10, 20, 50, 100]"
|
||||||
|
:page-size="pageSize"
|
||||||
|
:total="totalPage"
|
||||||
|
layout="total, sizes, prev, pager, next, jumper"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'StockRecordList',
|
||||||
|
props: {
|
||||||
|
bizType: {
|
||||||
|
type: Number,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
quantityLabel: {
|
||||||
|
type: String,
|
||||||
|
default: '数量'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
merchantId: '2',
|
||||||
|
dataForm: {
|
||||||
|
productName: '',
|
||||||
|
dateRange: null
|
||||||
|
},
|
||||||
|
dataList: [],
|
||||||
|
pageIndex: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
totalPage: 0,
|
||||||
|
remainTotalStock: null,
|
||||||
|
dataListLoading: false,
|
||||||
|
exportLoading: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
activated() {
|
||||||
|
this.getDataList()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleSearch() {
|
||||||
|
this.pageIndex = 1
|
||||||
|
this.getDataList()
|
||||||
|
},
|
||||||
|
changeTab() {
|
||||||
|
this.pageIndex = 1
|
||||||
|
this.getDataList()
|
||||||
|
},
|
||||||
|
getQueryParams() {
|
||||||
|
const params = {
|
||||||
|
current: this.pageIndex,
|
||||||
|
limit: this.pageSize,
|
||||||
|
merchantId: Number(this.merchantId),
|
||||||
|
bizType: this.bizType
|
||||||
|
}
|
||||||
|
if (this.dataForm.productName) {
|
||||||
|
params.productName = this.dataForm.productName
|
||||||
|
}
|
||||||
|
if (this.dataForm.dateRange && this.dataForm.dateRange.length === 2) {
|
||||||
|
params.startTime = this.dataForm.dateRange[0]
|
||||||
|
params.endTime = this.dataForm.dateRange[1]
|
||||||
|
}
|
||||||
|
return params
|
||||||
|
},
|
||||||
|
getDataList() {
|
||||||
|
this.dataListLoading = true
|
||||||
|
this.$http.request({
|
||||||
|
url: this.$http.adornUrl('/master/inventoryManagement/getStockRecordList'),
|
||||||
|
method: 'POST',
|
||||||
|
data: this.getQueryParams(),
|
||||||
|
header: { 'Content-Type': 'application/json' }
|
||||||
|
}).then(({ data }) => {
|
||||||
|
if (data && data.code === 0) {
|
||||||
|
this.dataList = data.result.records || []
|
||||||
|
this.totalPage = data.result.total || 0
|
||||||
|
this.pageIndex = data.result.current || this.pageIndex
|
||||||
|
this.remainTotalStock = data.result.remainTotalStock
|
||||||
|
} else {
|
||||||
|
this.dataList = []
|
||||||
|
this.totalPage = 0
|
||||||
|
this.remainTotalStock = null
|
||||||
|
}
|
||||||
|
this.dataListLoading = false
|
||||||
|
}).catch(() => {
|
||||||
|
this.dataList = []
|
||||||
|
this.totalPage = 0
|
||||||
|
this.remainTotalStock = null
|
||||||
|
this.dataListLoading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
sizeChangeHandle(val) {
|
||||||
|
this.pageSize = val
|
||||||
|
this.pageIndex = 1
|
||||||
|
this.getDataList()
|
||||||
|
},
|
||||||
|
currentChangeHandle(val) {
|
||||||
|
this.pageIndex = val
|
||||||
|
this.getDataList()
|
||||||
|
},
|
||||||
|
formatTime(time) {
|
||||||
|
if (!time) return '-'
|
||||||
|
return String(time).replace('T', ' ').slice(0, 19)
|
||||||
|
},
|
||||||
|
formatSource(source) {
|
||||||
|
const map = { other: '其他', zm: '众妙', ls: '灵枢' }
|
||||||
|
return map[source] || source || '-'
|
||||||
|
},
|
||||||
|
handleExport() {
|
||||||
|
this.exportLoading = true
|
||||||
|
this.$http({
|
||||||
|
url: this.$http.adornUrl('/master/inventoryManagement/exportStockRecordList'),
|
||||||
|
method: 'post',
|
||||||
|
data: this.$http.adornData(this.getQueryParams()),
|
||||||
|
responseType: 'blob'
|
||||||
|
}).then(res => {
|
||||||
|
const blob = new Blob([res.data], {
|
||||||
|
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||||||
|
})
|
||||||
|
const link = document.createElement('a')
|
||||||
|
link.href = window.URL.createObjectURL(blob)
|
||||||
|
const merchantPrefix = this.merchantId === '2' ? '众妙' : '灵枢'
|
||||||
|
const recordName = this.bizType === 1 ? '入库记录' : '出库记录'
|
||||||
|
link.download = `${merchantPrefix}${recordName}.xlsx`
|
||||||
|
link.click()
|
||||||
|
window.URL.revokeObjectURL(link.href)
|
||||||
|
this.$message.success('导出成功')
|
||||||
|
}).catch(() => {
|
||||||
|
this.$message.error('导出失败')
|
||||||
|
}).finally(() => {
|
||||||
|
this.exportLoading = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.summary-bar {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.summary-value {
|
||||||
|
color: #17b3a3;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
238
src/views/modules/inventoryManagement/inventoryManage.vue
Normal file
238
src/views/modules/inventoryManagement/inventoryManage.vue
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
<template>
|
||||||
|
<div class="mod-config">
|
||||||
|
<el-tabs v-model="merchantId" type="card" @tab-click="changeTab">
|
||||||
|
<el-tab-pane label="众妙之门" name="2" />
|
||||||
|
<el-tab-pane label="灵枢教育科技" name="1" />
|
||||||
|
</el-tabs>
|
||||||
|
|
||||||
|
<el-form
|
||||||
|
:inline="true"
|
||||||
|
:model="dataForm"
|
||||||
|
@keyup.enter.native="handleSearch"
|
||||||
|
>
|
||||||
|
<el-form-item label="商品名称">
|
||||||
|
<el-input
|
||||||
|
v-model="dataForm.productName"
|
||||||
|
placeholder="商品名称"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="库存状态">
|
||||||
|
<el-select v-model="dataForm.isAlert" placeholder="请选择" style="width: 120px">
|
||||||
|
<el-option label="全部" :value="0" />
|
||||||
|
<el-option label="仅预警" :value="1" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-date-picker
|
||||||
|
v-model="dataForm.dateRange"
|
||||||
|
type="daterange"
|
||||||
|
value-format="yyyy-MM-dd"
|
||||||
|
range-separator="至"
|
||||||
|
start-placeholder="开始日期"
|
||||||
|
end-placeholder="结束日期"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button @click="handleSearch">查询</el-button>
|
||||||
|
<el-button type="success" :loading="exportLoading" @click="handleExport">导出</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<div class="action-bar">
|
||||||
|
<el-button type="primary" @click="openPurchase(1)">入库</el-button>
|
||||||
|
<el-button type="warning" @click="openPurchase(2)">出库</el-button>
|
||||||
|
<el-button type="warning" @click="openBatchOutbound">批量出库</el-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-table
|
||||||
|
:data="dataList"
|
||||||
|
border
|
||||||
|
v-loading="dataListLoading"
|
||||||
|
height="60vh"
|
||||||
|
style="width: 100%"
|
||||||
|
:row-class-name="tableRowClassName"
|
||||||
|
>
|
||||||
|
<el-table-column prop="productId" label="商品ID" width="90" align="center" />
|
||||||
|
<el-table-column prop="productName" label="商品名称" align="center" min-width="180" />
|
||||||
|
<el-table-column prop="merchantLabel" label="商户" width="100" align="center" />
|
||||||
|
<el-table-column prop="purchaseTotal" label="入库总量" width="100" align="center" />
|
||||||
|
<el-table-column prop="saleTotal" label="出库总量" width="100" align="center" />
|
||||||
|
<el-table-column prop="remainTotal" label="剩余库存" width="100" align="center">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span class="remain-total">{{ scope.row.remainTotal }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="剩余比率" width="100" align="center">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
{{ formatRate(scope.row.remainRate) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<el-pagination
|
||||||
|
@size-change="sizeChangeHandle"
|
||||||
|
@current-change="currentChangeHandle"
|
||||||
|
:current-page="pageIndex"
|
||||||
|
:page-sizes="[10, 20, 50, 100]"
|
||||||
|
:page-size="pageSize"
|
||||||
|
:total="totalPage"
|
||||||
|
layout="total, sizes, prev, pager, next, jumper"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<purchase-dialog ref="purchaseDialog" @success="getDataList" />
|
||||||
|
<batch-outbound-dialog ref="batchOutboundDialog" @success="getDataList" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import PurchaseDialog from './components/purchaseDialog.vue'
|
||||||
|
import BatchOutboundDialog from './components/batchOutboundDialog.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
PurchaseDialog,
|
||||||
|
BatchOutboundDialog
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
merchantId: '2',
|
||||||
|
dataForm: {
|
||||||
|
productName: '',
|
||||||
|
isAlert: 0,
|
||||||
|
dateRange: null
|
||||||
|
},
|
||||||
|
dataList: [],
|
||||||
|
pageIndex: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
totalPage: 0,
|
||||||
|
dataListLoading: false,
|
||||||
|
exportLoading: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
activated() {
|
||||||
|
this.applyRouteQuery()
|
||||||
|
this.getDataList()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
applyRouteQuery() {
|
||||||
|
const isAlert = this.$route.query.isAlert
|
||||||
|
if (isAlert !== undefined && isAlert !== '') {
|
||||||
|
this.dataForm.isAlert = Number(isAlert) || 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleSearch() {
|
||||||
|
this.pageIndex = 1
|
||||||
|
this.getDataList()
|
||||||
|
},
|
||||||
|
changeTab() {
|
||||||
|
this.dataForm.productName = ''
|
||||||
|
this.pageIndex = 1
|
||||||
|
this.getDataList()
|
||||||
|
},
|
||||||
|
getQueryParams() {
|
||||||
|
const params = {
|
||||||
|
merchantId: Number(this.merchantId),
|
||||||
|
current: this.pageIndex,
|
||||||
|
limit: this.pageSize,
|
||||||
|
isAlert: this.dataForm.isAlert
|
||||||
|
}
|
||||||
|
if (this.dataForm.productName) {
|
||||||
|
params.productName = this.dataForm.productName
|
||||||
|
}
|
||||||
|
if (this.dataForm.dateRange && this.dataForm.dateRange.length === 2) {
|
||||||
|
params.startTime = this.dataForm.dateRange[0]
|
||||||
|
params.endTime = this.dataForm.dateRange[1]
|
||||||
|
}
|
||||||
|
return params
|
||||||
|
},
|
||||||
|
getDataList() {
|
||||||
|
this.dataListLoading = true
|
||||||
|
this.$http.request({
|
||||||
|
url: this.$http.adornUrl('/master/inventoryManagement/stockStatistics'),
|
||||||
|
method: 'POST',
|
||||||
|
data: this.getQueryParams(),
|
||||||
|
header: { 'Content-Type': 'application/json' }
|
||||||
|
}).then(({ data }) => {
|
||||||
|
if (data && data.code === 0) {
|
||||||
|
this.dataList = data.result.records || []
|
||||||
|
this.totalPage = data.result.total || 0
|
||||||
|
this.pageIndex = data.result.current || this.pageIndex
|
||||||
|
} else {
|
||||||
|
this.dataList = []
|
||||||
|
this.totalPage = 0
|
||||||
|
}
|
||||||
|
this.dataListLoading = false
|
||||||
|
}).catch(() => {
|
||||||
|
this.dataList = []
|
||||||
|
this.totalPage = 0
|
||||||
|
this.dataListLoading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
sizeChangeHandle(val) {
|
||||||
|
this.pageSize = val
|
||||||
|
this.pageIndex = 1
|
||||||
|
this.getDataList()
|
||||||
|
},
|
||||||
|
currentChangeHandle(val) {
|
||||||
|
this.pageIndex = val
|
||||||
|
this.getDataList()
|
||||||
|
},
|
||||||
|
formatRate(rate) {
|
||||||
|
if (rate == null) return '-'
|
||||||
|
return (Number(rate) * 100).toFixed(2) + '%'
|
||||||
|
},
|
||||||
|
tableRowClassName({ row }) {
|
||||||
|
if (row.remainRate != null && Number(row.remainRate) <= 0.3) {
|
||||||
|
return 'row-low-stock'
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
},
|
||||||
|
openPurchase(bizType) {
|
||||||
|
this.$refs.purchaseDialog.open(bizType, Number(this.merchantId))
|
||||||
|
},
|
||||||
|
openBatchOutbound() {
|
||||||
|
this.$refs.batchOutboundDialog.open(Number(this.merchantId))
|
||||||
|
},
|
||||||
|
handleExport() {
|
||||||
|
this.exportLoading = true
|
||||||
|
this.$http({
|
||||||
|
url: this.$http.adornUrl('/master/inventoryManagement/exportStockStatistics'),
|
||||||
|
method: 'post',
|
||||||
|
data: this.$http.adornData(this.getQueryParams()),
|
||||||
|
responseType: 'blob'
|
||||||
|
}).then(res => {
|
||||||
|
const blob = new Blob([res.data], {
|
||||||
|
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||||||
|
})
|
||||||
|
const link = document.createElement('a')
|
||||||
|
link.href = window.URL.createObjectURL(blob)
|
||||||
|
const merchantPrefix = this.merchantId === '2' ? '众妙' : '灵枢'
|
||||||
|
link.download = `${merchantPrefix}库存统计.xlsx`
|
||||||
|
link.click()
|
||||||
|
window.URL.revokeObjectURL(link.href)
|
||||||
|
this.$message.success('导出成功')
|
||||||
|
}).catch(() => {
|
||||||
|
this.$message.error('导出失败')
|
||||||
|
}).finally(() => {
|
||||||
|
this.exportLoading = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.action-bar {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
/deep/ .el-table .row-low-stock{
|
||||||
|
td {
|
||||||
|
background-color: #fffaf2 !important;
|
||||||
|
}
|
||||||
|
.remain-total {
|
||||||
|
color: #f56c6c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
11
src/views/modules/inventoryManagement/stockInRecord.vue
Normal file
11
src/views/modules/inventoryManagement/stockInRecord.vue
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<template>
|
||||||
|
<stock-record-list :biz-type="1" quantity-label="入库数量" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import StockRecordList from './components/stockRecordList.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: { StockRecordList }
|
||||||
|
}
|
||||||
|
</script>
|
||||||
11
src/views/modules/inventoryManagement/stockOutRecord.vue
Normal file
11
src/views/modules/inventoryManagement/stockOutRecord.vue
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<template>
|
||||||
|
<stock-record-list :biz-type="2" quantity-label="出库数量" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import StockRecordList from './components/stockRecordList.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: { StockRecordList }
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -122,6 +122,7 @@
|
|||||||
<el-input
|
<el-input
|
||||||
v-model="dataForm.productStock"
|
v-model="dataForm.productStock"
|
||||||
placeholder="商品库存"
|
placeholder="商品库存"
|
||||||
|
:disabled="dataForm.goodsType !== '05'"
|
||||||
></el-input>
|
></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -172,6 +172,7 @@
|
|||||||
<el-input
|
<el-input
|
||||||
v-model="dataForm.productStock"
|
v-model="dataForm.productStock"
|
||||||
placeholder="商品库存"
|
placeholder="商品库存"
|
||||||
|
:disabled="dataForm.goodsType !== '05'"
|
||||||
></el-input>
|
></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
@@ -323,7 +324,7 @@ export default {
|
|||||||
showBtnDealImg: true,
|
showBtnDealImg: true,
|
||||||
noneBtnImg: false,
|
noneBtnImg: false,
|
||||||
productName: "",
|
productName: "",
|
||||||
productStock: null, // 商品库存
|
productStock: 0, // 商品库存
|
||||||
price: "",
|
price: "",
|
||||||
author: "",
|
author: "",
|
||||||
publisher: "",
|
publisher: "",
|
||||||
|
|||||||
@@ -210,13 +210,6 @@
|
|||||||
@showchooseBookf="showchooseBookf"
|
@showchooseBookf="showchooseBookf"
|
||||||
></curriculum>
|
></curriculum>
|
||||||
|
|
||||||
<add-or-update
|
|
||||||
v-if="addOrUpdateVisible"
|
|
||||||
ref="addOrUpdate"
|
|
||||||
@refreshDataList="getDataList"
|
|
||||||
@showchooseBookf="showchooseBookf"
|
|
||||||
></add-or-update>
|
|
||||||
|
|
||||||
<commonTags ref="commonTags"></commonTags>
|
<commonTags ref="commonTags"></commonTags>
|
||||||
<correlation ref="correlation"></correlation>
|
<correlation ref="correlation"></correlation>
|
||||||
<choose-book v-if="chooseBookVisible" :bookIds = bookIds ref="chooseBook" :chooseBookVisible = chooseBookVisible @closeBookf = "closeBookf"></choose-book>
|
<choose-book v-if="chooseBookVisible" :bookIds = bookIds ref="chooseBook" :chooseBookVisible = chooseBookVisible @closeBookf = "closeBookf"></choose-book>
|
||||||
|
|||||||
@@ -16,17 +16,20 @@
|
|||||||
<el-popover
|
<el-popover
|
||||||
ref="menuListPopover"
|
ref="menuListPopover"
|
||||||
placement="bottom-start"
|
placement="bottom-start"
|
||||||
trigger="click">
|
trigger="click"
|
||||||
<el-tree
|
popper-class="mod-menu__tree-popover">
|
||||||
:data="menuList"
|
<div class="mod-menu__tree-inner">
|
||||||
:props="menuListTreeProps"
|
<el-tree
|
||||||
node-key="menuId"
|
:data="menuList"
|
||||||
ref="menuListTree"
|
:props="menuListTreeProps"
|
||||||
@current-change="menuListTreeCurrentChangeHandle"
|
node-key="menuId"
|
||||||
:default-expand-all="true"
|
ref="menuListTree"
|
||||||
:highlight-current="true"
|
@current-change="menuListTreeCurrentChangeHandle"
|
||||||
:expand-on-click-node="false">
|
:default-expand-all="true"
|
||||||
</el-tree>
|
:highlight-current="true"
|
||||||
|
:expand-on-click-node="false">
|
||||||
|
</el-tree>
|
||||||
|
</div>
|
||||||
</el-popover>
|
</el-popover>
|
||||||
<el-input v-model="dataForm.parentName" v-popover:menuListPopover :readonly="true" placeholder="点击选择上级菜单" class="menu-list__input"></el-input>
|
<el-input v-model="dataForm.parentName" v-popover:menuListPopover :readonly="true" placeholder="点击选择上级菜单" class="menu-list__input"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@@ -228,6 +231,14 @@
|
|||||||
width: 458px;
|
width: 458px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
&__tree-popover {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
&__tree-inner {
|
||||||
|
max-height: 300px;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
&__icon-inner {
|
&__icon-inner {
|
||||||
width: 478px;
|
width: 478px;
|
||||||
max-height: 258px;
|
max-height: 258px;
|
||||||
|
|||||||
Reference in New Issue
Block a user