采购审批

This commit is contained in:
DESKTOP-8FGKA8Q\chunfen 2025-08-29 17:25:42 +08:00
parent 41e848d46d
commit 036d902c41
18 changed files with 3241 additions and 71 deletions

View File

@ -71,4 +71,23 @@ body .el-page-header__back{
left: 60px;
transform: none;
}
.h5Tit{
background-color: #cad1e5;
height: 32px;
line-height: 32px;
margin-bottom: 15px;
padding-left: 20px;
position: relative;
color: #333;
font-size: 14px;
&::before{
position: absolute;
left: 10px;
top: 9px;
height: 14px;
background-color: var(--el-color-primary);
content: '';
width: 3px;
}
}
</style>

View File

@ -0,0 +1,292 @@
<template>
<el-dialog v-model="showDialog" title="尾款打款审批" width="1200px" @close="closeDialog">
<div v-loading="loading">
<div class="h5Tit">商品信息</div>
<el-table :data="goodsList" style="width: 100%;margin-top: 15px;" border>
<el-table-column prop="goods.title" label="商品名称" />
<el-table-column label="规格名称">
<template #default="scope">
<span>{{ scope.row.sku && scope.row.sku.title || scope.row.title }}</span>
</template>
</el-table-column>
<el-table-column prop="unit" label="单位" align="center" />
<el-table-column prop="expect_unit_price" label="预计产品单价(含税)" align="center" />
<el-table-column label="实际产品单价(含税)" align="center">
<template #default="scope">
<el-input class="inpt" type="text" v-model="scope.row.real_unit_price" @input="changeInput" />
</template>
</el-table-column>
<el-table-column prop="expect_quantity" label="预计采购数量" align="center" />
<el-table-column label="实际采购数量" align="center">
<template #default="scope">
<el-input class="inpt" type="text" v-model="scope.row.real_quantity" @input="changeInput" />
</template>
</el-table-column>
<el-table-column prop="expect_amount" label="预计订单金额" align="center" />
<el-table-column prop="real_amount" label="实际订单金额" align="center" />
<el-table-column prop="has_paid_amount" label="已打款" align="center" />
<el-table-column label="申请打款金额" align="center">
<template #default="scope">
<el-input type="text" class="inpt" v-model="scope.row.apply_amount" @input="changeApply" />
</template>
</el-table-column>
</el-table>
<div class="h5Tit">其他费用</div>
<el-button type="primary" @click="addFee">添加其他费用</el-button>
<el-table :data="feesList" style="width: 100%;margin-top: 15px;" border>
<el-table-column label="费用名称" align="center">
<template #default="scope">
<el-input type="text" v-model="scope.row.fee_name" :disabled="scope.row.id" />
</template>
</el-table-column>
<el-table-column label="订单金额">
<template #default="scope">
<el-input type="text" v-model="scope.row.amount" :disabled="scope.row.id" />
</template>
</el-table-column>
<el-table-column label="打款信息">
<template #default="scope">
<el-select v-model="scope.row.other_expense_account_id" placeholder="请选择" clearable filterable :disabled="scope.row.id">
<el-option v-for="it in accountList" :key="it.id" :label="it.name" :value="it.id" />
</el-select>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="100">
<template #default="scope">
<el-button type="danger" :disabled="scope.row.id" size="mini" @click="removeFee(scope.$index)"><el-icon><DeleteFilled /></el-icon></el-button>
</template>
</el-table-column>
</el-table>
<div style="padding: 20px 0;color: #f00;">合计申请打款金额{{total_amount}}</div>
<div class="huibox">
<div>
打款前总实际订单金额{{itemInfo.total_amount}}
总实际已支付金额{{itemInfo.has_paid_amount}}
总实际未支付金额{{ ((itemInfo.total_amount * 100 - itemInfo.has_paid_amount * 100) / 100).toFixed(2) }}
</div>
<div>
打款后总实际订单金额{{real_total_amount}}
总实际已支付金额{{ ((itemInfo.has_paid_amount * 100 + total_amount * 100) / 100).toFixed(2) }}
总实际未支付金额{{ ((real_total_amount * 100 - itemInfo.has_paid_amount * 100 - total_amount * 100) / 100).toFixed(2) }}
</div>
</div>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="closeDialog()">取消</el-button>
<el-button type="primary" @click="commitApproval()" :loading="btnloading">提交审批</el-button>
</span>
</template>
</el-dialog>
</template>
<script>
import { DeleteFilled, Search } from "@element-plus/icons"
import { reactive, toRefs, watch } from 'vue'
import { get, post } from '@/api/request'
import { ElMessage } from 'element-plus'
export default {
components: { DeleteFilled, Search },
props: {
show: {
type: Boolean,
default: false
},
id: {
type: Number,
default: 0,
}
},
setup(props, context) {
const data = reactive({
launchId: 0,
showDialog: false,
accountList: [],
goodsList: [],
loading: false,
feesList: [],
btnloading: false,
total_amount: 0,
real_total_amount: 0,
itemInfo: {}
})
function getDetail() {
data.loading = true
get(`/api/purchaseOrder/${data.launchId}`).then((res) => {
data.itemInfo = res.data
data.feesList = res.data.other_expenses
data.goodsList = res.data.products
data.loading = false
}).catch(() => {
data.loading = false
})
}
function getAccount() {
get(`/api/otherExpenseAccount`, {page: 1, pageSize: 1000}).then((res) => {
data.accountList = res.data
})
}
const commitApproval = () => {
data.btnloading = true
let products = []
for (let index = 0; index < data.goodsList.length; index++) {
let obj = data.goodsList[index]
products.push({
id: obj.id,
product_id: obj.product_id,
sku_id: obj.id,
real_unit_price: obj.real_unit_price,
real_quantity: obj.real_quantity,
apply_amount: obj.apply_amount
})
}
let params = {
purchase_order_id: data.launchId,
products: products,
otherExpenses: data.feesList
}
post(`/api/purchaseOrder/finalPaymentSubmit`, params).then((res) => {
ElMessage({ type: 'success', message: '提交成功' })
closeDialog()
context.emit('refresh')
data.btnloading = false
}).catch(() => {
data.btnloading = false
})
}
function clearForm() {
data.feesList = []
data.goodsList = []
}
const closeDialog = () => {
clearForm()
context.emit('close')
data.showDialog = false
}
function addFee() {
data.feesList.push({
fee_name: '',
amount: '',
other_expense_account_id: ''
})
}
function removeFee(i) {
data.feesList.splice(i, 1)
}
function getTotalAmount() {
let num = 0, total = 0
for (let index = 0; index < data.goodsList.length; index++) {
let item = data.goodsList[index]
if(item.apply_amount) {
num += item.apply_amount * 100
total += item.apply_amount * 100
} else if(item.real_unit_price && item.real_quantity) {
let real_amount = item.real_unit_price * item.real_quantity
num += real_amount * 100 - item.has_paid_amount * 100
total += real_amount * 100
}
}
for (let index = 0; index < data.feesList.length; index++) {
let item = data.feesList[index]
if(item.amount && item.has_paid_amount * 1 > 0) {
total += item.amount * 100
if(!item.id && item.amount) {
num += item.amount * 100
}
}
}
data.total_amount = (num / 100).toFixed(2)
data.real_total_amount = (total / 100).toFixed(2)
}
function changeInput(){
for (let index = 0; index < data.goodsList.length; index++) {
let item = data.goodsList[index]
if(item.real_unit_price && item.real_quantity) {
item.real_amount = item.real_unit_price * item.real_quantity
item.apply_amount = ((item.real_amount * 100 - item.has_paid_amount * 100) / 100).toFixed(2)
}
}
getTotalAmount()
}
function changeApply() {
let num = 0, total = 0
for (let index = 0; index < data.goodsList.length; index++) {
let item = data.goodsList[index]
num += item.apply_amount * 100
total += item.apply_amount * 100
}
for (let index = 0; index < data.feesList.length; index++) {
let item = data.feesList[index]
if(item.amount && item.has_paid_amount * 1 > 0) {
total += item.amount * 100
if(!item.id && item.amount) {
num += item.amount * 100
}
}
}
data.total_amount = (num / 100).toFixed(2)
data.real_total_amount = (total / 100).toFixed(2)
}
watch(() => data.feesList, (newProps) => {
getTotalAmount()
}, { deep: true })
watch(() => props, (newProps) => {
if (newProps.show) {
data.showDialog = true
data.launchId = newProps.id
if(data.launchId) {
getDetail()
}
getAccount()
}
}, { deep: true })
return {
...toRefs(data),
changeInput,
getDetail,
getAccount,
closeDialog,
clearForm,
commitApproval,
addFee,
removeFee,
getTotalAmount,
changeApply
}
}
}
</script>
<style scoped lang="scss">
::v-deep .inpt .el-input__inner{
text-align: center;
}
.h5Tit{
margin-top: 20px;
}
.huibox{
background-color: #f5f5f5;
padding: 15px;
line-height: 30px;
border-left: 3px solid #3c8dbc;
}
</style>

View File

@ -0,0 +1,96 @@
<template>
<el-dialog v-model="showDialog" title="审批记录" width="700px" @close="closeDialog">
<div style="padding-top: 30px;">
<el-timeline style="max-width: 600px">
<el-timeline-item v-for="(item, index) in logsList" :key="index">
<div><span style="color: #f00;">{{Status[item.status]}}</span>#{{Type[item.type]}}</div>
<div style="color: #888;padding-top:5px;">{{item.created_at}}</div>
<div style="padding-top: 30px;" v-if="item.records.length">
<el-timeline style="max-width: 600px">
<el-timeline-item v-for="it in item.records" :key="it.id" :timestamp="it.created_at">
<div>
<span style="color: #00C297;">@{{it.admin_user && it.admin_user.username}}</span>
<span style="color: #f00;">{{Status[it.node_status]}}</span>
</div>
<span style="color: #666;" v-if="it.comments">原因{{it.comments}}</span>
</el-timeline-item>
</el-timeline>
</div>
</el-timeline-item>
</el-timeline>
</div>
</el-dialog>
</template>
<script>
import { Plus, Search } from "@element-plus/icons"
import { reactive, toRefs, watch } from 'vue'
import { get } from '@/api/request'
export default {
components: { Plus, Search },
props: {
show: {
type: Boolean,
default: false
},
id: {
type: Number,
default: 0,
}
},
setup(props, context) {
const data = reactive({
launchId: 0,
showDialog: false,
loading: false,
Type: {
'1': '采购订单审批',
'2': '预付款打款审批',
'3': '尾款打款审批',
'4': '已结束'
},
Status: {
'1': '提交了审批',
'2': '同意了审批',
'3': '驳回了审批',
'4': '上传凭证'
},
logsList: []
})
function getDetail() {
data.loading = true
get(`/api/purchaseOrder/orderInstanceList`, {purchase_order_id: data.launchId}).then((res) => {
data.logsList = res.data
data.loading = false
}).catch(() => {
data.loading = false
})
}
const closeDialog = () => {
context.emit('close')
data.showDialog = false
}
watch(() => props, (newProps) => {
if (newProps.show) {
data.showDialog = true
data.launchId = newProps.id
getDetail()
}
}, { deep: true })
return {
...toRefs(data),
closeDialog,
getDetail,
}
}
}
</script>
<style scoped lang="scss">
</style>

View File

@ -0,0 +1,522 @@
<template>
<el-dialog v-model="showDialog" title="采购订单审批" width="1200px" @close="closeDialog">
<el-form label-position="right" label-width="110px" v-loading="loading" :disabled="elType == 'view'">
<el-form-item label="公司名称:">
<el-select v-model="itemInfo.company_id" placeholder="请选择" clearable filterable style="width: 320px;">
<el-option v-for="it in companyList" :key="it.id" :label="it.name" :value="it.id" />
</el-select>
</el-form-item>
<el-form-item label="选品:">
<el-select v-model="itemInfo.manager_id" placeholder="请选择" clearable filterable style="width: 320px;">
<el-option v-for="it in managerList" :key="it.id" :label="it.username" :value="it.id" />
</el-select>
</el-form-item>
<el-form-item label="供应商名称:">
<el-select v-model="itemInfo.purchase_supplier_id" placeholder="请选择" clearable filterable style="width: 320px;">
<el-option v-for="it in supplierList" :key="it.id" :label="it.supplier_name" :value="it.id" />
</el-select>
</el-form-item>
<el-form-item label="商品信息:">
<el-button type="primary" @click="openGoods()">添加商品</el-button>
<el-table :data="goodsList" style="width: 100%;margin-top: 15px;" border>
<el-table-column prop="goods.title" label="商品名称" />
<el-table-column label="规格名称">
<template #default="scope">
<span>{{ scope.row.sku && scope.row.sku.title || scope.row.title }}</span>
</template>
</el-table-column>
<el-table-column label="预计产品单价(含税)" align="center">
<template #default="scope">
<el-input class="inpt" type="text" v-model="scope.row.expect_unit_price" />
</template>
</el-table-column>
<el-table-column label="单位" align="center">
<template #default="scope">
<el-input class="inpt" type="text" v-model="scope.row.unit" />
</template>
</el-table-column>
<el-table-column label="预计采购数量" align="center">
<template #default="scope">
<el-input class="inpt" type="text" v-model="scope.row.expect_quantity" />
</template>
</el-table-column>
<el-table-column label="预付款比例(%)" align="center">
<template #default="scope">
<div style="display: flex;align-items: center;"><el-input type="text" class="inpt" v-model="scope.row.prepayment_ratio" />&nbsp;%</div>
</template>
</el-table-column>
<el-table-column label="交货时间" width="160" align="center">
<template #default="scope">
<el-date-picker
v-model="scope.row.delivery_date"
type="date"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
placeholder="选择日期"
style="width: 130px;"
clearable>
</el-date-picker>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="100">
<template #default="scope">
<el-button type="danger" size="mini" @click="removeGoods(scope.$index, scope.row.product_id)"><el-icon><DeleteFilled /></el-icon></el-button>
</template>
</el-table-column>
</el-table>
</el-form-item>
<el-form-item label="其他费用:">
<el-button type="primary" @click="addFee">添加其他费用</el-button>
<el-table :data="feesList" style="width: 100%;margin-top: 15px;" border>
<el-table-column label="费用名称" align="center">
<template #default="scope">
<el-input type="text" v-model="scope.row.fee_name" />
</template>
</el-table-column>
<el-table-column label="订单金额">
<template #default="scope">
<el-input type="text" v-model="scope.row.amount" />
</template>
</el-table-column>
<el-table-column label="打款信息">
<template #default="scope">
<el-select v-model="scope.row.other_expense_account_id" placeholder="请选择" clearable filterable>
<el-option v-for="it in accountList" :key="it.id" :label="it.name" :value="it.id" />
</el-select>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="100">
<template #default="scope">
<el-button type="danger" size="mini" @click="removeFee(scope.$index)"><el-icon><DeleteFilled /></el-icon></el-button>
</template>
</el-table-column>
</el-table>
</el-form-item>
<el-form-item label="备注:">
<el-input v-model="itemInfo.remark" placeholder="请填写备注内容" type="textarea" :rows="4"></el-input>
</el-form-item>
<el-form-item label="逾期交货说明:">
<el-input v-model="itemInfo.late_delivery_explanation" placeholder="请填写逾期交货说明" type="textarea" :rows="4"></el-input>
</el-form-item>
<el-form-item label="总计:">
<div class="sumbox">
总预计订单金额<span>{{ sumData.total_amount || '0.00' }}</span>
总预付款<span>{{ sumData.pre_pay_amount || '0.00' }}</span>
总尾款<span>{{ sumData.balance_amount || '0.00' }}</span>
</div>
</el-form-item>
<div class="space"></div>
<div class="h5Tit">其余信息</div>
<el-form-item label="开团时间:">
<el-date-picker
v-model="itemInfo.sold_start_time"
type="datetime"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="请选择开团时间"
clearable>
</el-date-picker>
</el-form-item>
<el-form-item label="预计到仓时间:">
<el-date-picker
v-model="itemInfo.arrived_time"
type="datetime"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="预计到仓时间"
clearable>
</el-date-picker>
</el-form-item>
<el-form-item label="仓库:">
<el-input type="text" v-model="itemInfo.warehouse_name" placeholder="请输入仓库名称" clearable style="width: 320px;" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer" v-if="elType != 'view'">
<el-button @click="closeDialog()">取消</el-button>
<el-button type="primary" @click="commitApproval()" :loading="btnloading">提交审批</el-button>
</span>
</template>
</el-dialog>
<el-dialog v-model="showGoods" width="900px" title="添加商品">
<div class="searchBox">
<div class="row">
<span class="span">商品名称</span>
<div class="right">
<el-select v-model="filter.goodsIds" placeholder="请选择" clearable filterable class="wid100">
<el-option v-for="it in goodskuList" :key="it.id" :label="it.title" :value="it.id" />
</el-select>
</div>
</div>
<div class="row">
<span class="span">规格名称</span>
<div class="right"><el-input v-model="filter.title" class="wid100" clearable></el-input></div>
</div>
<div class="row">
<span class="span">规格编码</span>
<div class="right"><el-input v-model="filter.sku_code" class="wid100" clearable></el-input></div>
</div>
<el-button type="primary" @click="handleSearch"><el-icon><Search /></el-icon>&nbsp;筛选</el-button>
</div>
<el-table :data="tableList" style="width: 100%" border v-loading="loading1" @select="select"
ref="multipleTable" @select-all="selectAll">
<el-table-column type="selection" width="55" :selectable="checkSelect" />
<el-table-column prop="id" label="ID" width="80" align="center" />
<el-table-column prop="goods.title" label="商品名称" align="center" />
<el-table-column prop="goods.goods_code" label="商品货号" align="center" />
<el-table-column prop="title" label="规格名称" align="center" />
<el-table-column prop="sku_code" label="规格编码" align="center" />
</el-table>
<div class="page-pagination">
<el-pagination
:current-page="page"
background
layout="prev, pager, next, sizes, total"
:total="total"
:page-sizes="[10, 50, 100]"
:page-size="pageSize"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"></el-pagination>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="showGoods = false">取消</el-button>
<el-button type="primary" @click="addGoods">确定</el-button>
</span>
</template>
</el-dialog>
</template>
<script>
import { DeleteFilled, Search } from "@element-plus/icons"
import { reactive, toRefs, watch } from 'vue'
import { get, post } from '@/api/request'
import { ElMessage, ElMessageBox } from 'element-plus'
export default {
components: { DeleteFilled, Search },
props: {
show: {
type: Boolean,
default: false
},
id: {
type: Number,
default: 0,
},
type: {
type: String,
default: '',
}
},
setup(props, context) {
const data = reactive({
launchId: 0,
elType: '',
showDialog: false,
companyList: [],
managerList: [],
supplierList: [],
accountList: [],
goodsList: [],
itemInfo: {},
loading: false,
showGoods: false,
feesList: [],
goodskuList: [],
filter: {},
tableList: [],
page: 1,
pageSize: 10,
total: 0,
loading1: false,
chooseList: [],
btnloading: false,
goodsIds: [],
sumData: {}
})
function getDetail() {
data.loading = true
get(`/api/purchaseOrder/${data.launchId}`).then((res) => {
data.itemInfo = res.data
data.feesList = res.data.other_expenses
data.goodsList = res.data.products
res.data.products.forEach((item) => {
data.goodsIds.push(item.product_id)
})
data.loading = false
}).catch(() => {
data.loading = false
})
}
function getCompany() {
get(`/api/company/all`, {page: 1, pageSize: 1000}).then((res) => {
data.companyList = res.data
})
}
function getManagerList() {
get('/api/staff', {role_id: 1}).then((res) => {
data.managerList = res.data
})
}
function getSupplier() {
get(`/api/purchaseSupplier`, {page: 1, pageSize: 1000}).then((res) => {
data.supplierList = res.data
})
}
function getAccount() {
get(`/api/otherExpenseAccount`, {page: 1, pageSize: 1000}).then((res) => {
data.accountList = res.data
})
}
const commitApproval = () => {
data.btnloading = true
let products = []
for (let index = 0; index < data.goodsList.length; index++) {
let obj = data.goodsList[index]
products.push({
product_id: obj.goods_id,
sku_id: obj.sku_id,
expect_unit_price: obj.expect_unit_price,
expect_quantity: obj.expect_quantity,
unit: obj.unit,
prepayment_ratio: obj.prepayment_ratio,
delivery_date: obj.delivery_date
})
}
let params = {
company_id: data.itemInfo.company_id,
manager_id: data.itemInfo.manager_id,
purchase_supplier_id: data.itemInfo.purchase_supplier_id,
products: products,
otherExpenses: data.feesList,
remark: data.itemInfo.remark,
late_delivery_explanation: data.itemInfo.late_delivery_explanation,
sold_start_time: data.itemInfo.sold_start_time,
arrived_time: data.itemInfo.arrived_time,
warehouse_name: data.itemInfo.warehouse_name
}
post(`/api/purchaseOrder`, params).then((res) => {
ElMessage({ type: 'success', message: '操作成功' })
closeDialog()
context.emit('refresh')
data.btnloading = false
}).catch(() => {
data.btnloading = false
})
}
function clearForm() {
data.itemInfo = {}
data.feesList = []
data.goodsList = []
data.goodsIds = []
}
function getGoodskuList() {
get(`/api/all/goods`).then((res) => {
data.goodskuList = res.data
})
}
function handleSearch() {
data.page = 1
fetchData()
}
const fetchData = () => {
data.loading1 = true
let params = {
page: data.page,
pageSize: data.pageSize,
...data.filter,
}
get(`/api/goods-skus`, params).then((res) => {
data.tableList = res.data
data.total = res.meta.total
data.loading1 = false
data.chooseList = []
}).catch(() => {
data.loading1 = false
})
}
function handleCurrentChange(e) {
data.page = e
fetchData()
}
function handleSizeChange(e) {
data.page = 1
data.pageSize = e
fetchData()
}
const closeDialog = () => {
clearForm()
context.emit('close')
data.showDialog = false
}
function select(e) {
data.chooseList = e
}
function selectAll(e) {
data.chooseList = e
}
function checkSelect(row) {
if (data.goodsIds.indexOf(row.id) >= 0) {
return false
} else {
return true
}
}
function addGoods() {
if(!data.chooseList.length) {
return ElMessage.info('请选择商品')
}
data.chooseList.forEach((item) => {
item.product_id = item.goods_id
item.sku_id = item.id
data.goodsList.push(item)
data.goodsIds.push(item.goods_id)
})
data.showGoods = false
}
function removeGoods(i, id) {
data.goodsList.splice(i, 1)
let index = data.goodsIds.indexOf(id)
data.goodsIds.splice(index, 1)
}
function addFee() {
data.feesList.push({
fee_name: '',
amount: '',
other_expense_account_id: ''
})
}
function removeFee(i) {
data.feesList.splice(i, 1)
}
function openGoods() {
data.showGoods = true
handleSearch()
}
watch(() => data.goodsList, (newProps) => {
let num1 = 0, num2 = 0, num3 = 0
for (let index = 0; index < newProps.length; index++) {
let item = newProps[index]
if(item.expect_unit_price && item.expect_quantity) {
num1 += item.expect_unit_price * item.expect_quantity
if(item.prepayment_ratio) {
num2 += num1 * item.prepayment_ratio
num3 += num1 * 100 - num2
}
}
}
data.sumData.total_amount = num1.toFixed(2)
data.sumData.pre_pay_amount = (num2 / 100).toFixed(2)
data.sumData.balance_amount = (num3 / 100).toFixed(2)
}, { deep: true })
watch(() => props, (newProps) => {
if (newProps.show) {
data.showDialog = true
data.launchId = newProps.id
data.elType = newProps.type || ''
if(data.launchId) {
getDetail()
}
getCompany()
getManagerList()
getSupplier()
getGoodskuList()
getAccount()
}
}, { deep: true })
return {
...toRefs(data),
getDetail,
getAccount,
closeDialog,
getCompany,
getManagerList,
getSupplier,
clearForm,
commitApproval,
getGoodskuList,
handleSearch,
handleCurrentChange,
handleSizeChange,
select,
selectAll,
checkSelect,
addGoods,
removeGoods,
addFee,
removeFee,
openGoods
}
}
}
</script>
<style scoped lang="scss">
.searchBox{
display: flex;
flex-wrap: wrap;
background-color: #fff;
padding: 15px 0 0 0;
border-radius: 4px;
margin-bottom: 15px;
.row{
display: flex;
align-items: center;
width: 250px;
box-sizing: border-box;
margin-bottom: 15px;
.span{
display: block;
width: 80px;
font-size: 14px;
text-align: right;
box-sizing: border-box;
}
.right{
width: calc(100% - 100px);
}
.wid100{
width: 100%;
}
}
}
.space{
background: repeating-linear-gradient(-45deg, #F56C6C 0, #F56C6C 20%, transparent 0, transparent 25%, #1989fa 0, #1989fa 45%, transparent 0, transparent 50%);
height: 2px;
background-size: 80px;
margin-bottom: 20px;
}
::v-deep .inpt .el-input__inner{
text-align: center;
}
</style>

View File

@ -0,0 +1,146 @@
<template>
<el-dialog v-model="showDialog" title="预付款打款审批" width="700px" @close="closeDialog">
<el-form label-position="right" label-width="90px" v-loading="loading">
<el-form-item label="订单合同:">
<el-upload
ref="uploadRef"
action="/api/upload/img"
:headers="headers"
:on-remove="handleRemoveImg"
:on-error="handleUploadError"
:on-preview="handlePreview"
:on-success="handleSuccess"
:file-list="imgsList"
:show-file-list="true"
list-type="picture-card"
accept=".png,.jpg,.gif">
<el-icon><Plus /></el-icon>
</el-upload>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="closeDialog()">取消</el-button>
<el-button type="primary" @click="commitApproval()" :loading="loading">提交审批</el-button>
</span>
</template>
</el-dialog>
<!-- 预览图片 -->
<el-dialog v-model="picVisible" center width="800px">
<img :src="dialogImageUrl" style="max-width: 700px; margin: 0 auto;display: block;" />
</el-dialog>
</template>
<script>
import { Plus, Search } from "@element-plus/icons"
import { reactive, toRefs, watch, ref, nextTick } from 'vue'
import { get, post } from '@/api/request'
import { ElMessage } from 'element-plus'
export default {
components: { Plus, Search },
props: {
show: {
type: Boolean,
default: false
},
id: {
type: Number,
default: 0,
}
},
setup(props, context) {
const data = reactive({
headers: {
Authorization: localStorage.getItem('token'),
'Shop-Id': localStorage.getItem('shopId') || ''
},
picVisible: false,
dialogImageUrl: '',
launchId: 0,
showDialog: false,
imgsList: [],
loading: false,
})
const commitApproval = () => {
data.loading = true
let imgs = []
for (let index = 0; index < data.imgsList.length; index++) {
let obj = data.imgsList[index]
imgs.push(obj.url)
}
let params = {
purchase_order_id: data.launchId,
related_images: imgs
}
post(`/api/purchaseOrder/prepaymentSubmit`, params).then((res) => {
ElMessage({ type: 'success', message: '提交成功' })
closeDialog()
context.emit('refresh')
data.loading = false
}).catch(() => {
data.loading = false
})
}
function handleUploadError(err) {
if(JSON.parse(err.message) && JSON.parse(err.message).message) {
ElMessage({ type: 'error', message: JSON.parse(err.message).message })
}
}
function handleRemoveImg(res, ress) {
data.imgsList = ress
}
function handleSuccess(res) {
data.imgsList.push({url: res.data.link})
}
const uploadRef = ref(null)
function clearForm() {
data.imgsList = []
nextTick(() => {
uploadRef.value.clearFiles()
})
}
const closeDialog = () => {
clearForm()
context.emit('close')
data.showDialog = false
}
function handlePreview(File) {
data.dialogImageUrl = File.url
data.picVisible = true
}
watch(() => props, (newProps) => {
if (newProps.show) {
data.showDialog = true
data.launchId = newProps.id
}
}, { deep: true })
return {
uploadRef,
...toRefs(data),
closeDialog,
clearForm,
commitApproval,
handlePreview,
handleSuccess,
handleRemoveImg,
handleUploadError
}
}
}
</script>
<style scoped lang="scss">
</style>

View File

@ -0,0 +1,122 @@
<template>
<el-dialog v-model="showDialog" title="更新信息" width="700px" @close="closeDialog">
<el-form label-position="right" label-width="120px" v-loading="loading">
<el-form-item label="开团时间:">
<el-date-picker
v-model="itemInfo.sold_start_time"
type="datetime"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="请选择开团时间"
clearable>
</el-date-picker>
</el-form-item>
<el-form-item label="预计到仓时间:">
<el-date-picker
v-model="itemInfo.arrived_time"
type="datetime"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="预计到仓时间"
clearable>
</el-date-picker>
</el-form-item>
<el-form-item label="仓库:">
<el-input type="text" v-model="itemInfo.warehouse_name" placeholder="请输入仓库名称" clearable style="width: 320px;" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="closeDialog()">取消</el-button>
<el-button type="primary" @click="commitApproval()" :loading="loading">提交审批</el-button>
</span>
</template>
</el-dialog>
</template>
<script>
import { Plus, Search } from "@element-plus/icons"
import { reactive, toRefs, watch, ref, nextTick } from 'vue'
import { get, post } from '@/api/request'
import { ElMessage } from 'element-plus'
export default {
components: { Plus, Search },
props: {
show: {
type: Boolean,
default: false
},
id: {
type: Number,
default: 0,
}
},
setup(props, context) {
const data = reactive({
launchId: 0,
showDialog: false,
loading: false,
itemInfo: {}
})
function getDetail() {
data.loading = true
get(`/api/purchaseOrder/${data.launchId}`).then((res) => {
data.itemInfo = res.data
data.loading = false
}).catch(() => {
data.loading = false
})
}
const commitApproval = () => {
data.loading = true
let params = {
purchase_order_id: data.launchId,
sold_start_time: data.itemInfo.sold_start_time,
arrived_time: data.itemInfo.arrived_time,
warehouse_name: data.itemInfo.warehouse_name
}
post(`/api/purchaseOrder/updateOrderInfo`, params).then((res) => {
ElMessage({ type: 'success', message: '修改成功' })
closeDialog()
context.emit('refresh')
data.loading = false
}).catch(() => {
data.loading = false
})
}
function clearForm() {
data.itemInfo = {}
}
const closeDialog = () => {
clearForm()
context.emit('close')
data.showDialog = false
}
watch(() => props, (newProps) => {
if (newProps.show) {
data.showDialog = true
data.launchId = newProps.id
getDetail()
}
}, { deep: true })
return {
...toRefs(data),
closeDialog,
clearForm,
commitApproval,
getDetail,
}
}
}
</script>
<style scoped lang="scss">
</style>

View File

@ -0,0 +1,162 @@
<template>
<el-dialog v-model="showDialog" title="上传发票" width="700px" @close="closeDialog">
<el-form label-position="right" label-width="90px" v-loading="loading">
<el-form-item label="发票:">
<el-upload
ref="uploadRef"
action="/api/upload/img"
:headers="headers"
:on-remove="handleRemoveImg"
:on-error="handleUploadError"
:on-preview="handlePreview"
:on-success="handleSuccess"
:file-list="imgsList"
:show-file-list="true"
list-type="picture-card"
accept=".png,.jpg,.gif">
<el-icon><Plus /></el-icon>
</el-upload>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="closeDialog()">取消</el-button>
<el-button type="primary" @click="commitApproval()" :loading="loading">提交审批</el-button>
</span>
</template>
</el-dialog>
<!-- 预览图片 -->
<el-dialog v-model="picVisible" center width="800px">
<img :src="dialogImageUrl" style="max-width: 700px; margin: 0 auto;display: block;" />
</el-dialog>
</template>
<script>
import { Plus, Search } from "@element-plus/icons"
import { reactive, toRefs, watch, ref, nextTick } from 'vue'
import { get, post } from '@/api/request'
import { ElMessage } from 'element-plus'
export default {
components: { Plus, Search },
props: {
show: {
type: Boolean,
default: false
},
id: {
type: Number,
default: 0,
}
},
setup(props, context) {
const data = reactive({
headers: {
Authorization: localStorage.getItem('token'),
'Shop-Id': localStorage.getItem('shopId') || ''
},
picVisible: false,
dialogImageUrl: '',
launchId: 0,
showDialog: false,
imgsList: [],
loading: false,
})
function getDetail() {
data.loading = true
get(`/api/purchaseOrder/${data.launchId}`).then((res) => {
let list = res.data.invoice_images || []
list.forEach((item) => {
data.imgsList.push({url: item})
})
data.loading = false
}).catch(() => {
data.loading = false
})
}
const commitApproval = () => {
data.loading = true
let imgs = []
for (let index = 0; index < data.imgsList.length; index++) {
let obj = data.imgsList[index]
imgs.push(obj.url)
}
let params = {
purchase_order_id: data.launchId,
invoice_images: imgs
}
post(`/api/purchaseOrder/invoiceSubmit`, params).then((res) => {
ElMessage({ type: 'success', message: '提交成功' })
closeDialog()
context.emit('refresh')
data.loading = false
}).catch(() => {
data.loading = false
})
}
function handleUploadError(err) {
if(JSON.parse(err.message) && JSON.parse(err.message).message) {
ElMessage({ type: 'error', message: JSON.parse(err.message).message })
}
}
function handleRemoveImg(res, ress) {
data.imgsList = ress
}
function handleSuccess(res) {
data.imgsList.push({url: res.data.link})
}
const uploadRef = ref(null)
function clearForm() {
data.imgsList = []
data.imgsList = []
nextTick(() => {
uploadRef.value.clearFiles()
})
}
const closeDialog = () => {
clearForm()
context.emit('close')
data.showDialog = false
}
function handlePreview(File) {
data.dialogImageUrl = File.url
data.picVisible = true
}
watch(() => props, (newProps) => {
if (newProps.show) {
data.showDialog = true
data.launchId = newProps.id
getDetail()
}
}, { deep: true })
return {
uploadRef,
...toRefs(data),
closeDialog,
clearForm,
commitApproval,
handlePreview,
handleSuccess,
handleRemoveImg,
handleUploadError,
getDetail
}
}
}
</script>
<style scoped lang="scss">
</style>

View File

@ -0,0 +1,146 @@
<template>
<el-dialog v-model="showDialog" title="上传支付凭证" width="700px" @close="closeDialog">
<el-form label-position="right" label-width="90px" v-loading="loading">
<el-form-item label="支付凭证:">
<el-upload
ref="uploadRef"
action="/api/upload/img"
:headers="headers"
:on-remove="handleRemoveImg"
:on-error="handleUploadError"
:on-preview="handlePreview"
:on-success="handleSuccess"
:file-list="imgsList"
:show-file-list="true"
list-type="picture-card"
accept=".png,.jpg,.gif">
<el-icon><Plus /></el-icon>
</el-upload>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="closeDialog()">取消</el-button>
<el-button type="primary" @click="commitApproval()" :loading="loading">提交</el-button>
</span>
</template>
</el-dialog>
<!-- 预览图片 -->
<el-dialog v-model="picVisible" center width="800px">
<img :src="dialogImageUrl" style="max-width: 700px; margin: 0 auto;display: block;" />
</el-dialog>
</template>
<script>
import { Plus, Search } from "@element-plus/icons"
import { reactive, toRefs, watch, ref, nextTick } from 'vue'
import { get, post } from '@/api/request'
import { ElMessage } from 'element-plus'
export default {
components: { Plus, Search },
props: {
show: {
type: Boolean,
default: false
},
id: {
type: Number,
default: 0,
}
},
setup(props, context) {
const data = reactive({
headers: {
Authorization: localStorage.getItem('token'),
'Shop-Id': localStorage.getItem('shopId') || ''
},
picVisible: false,
dialogImageUrl: '',
launchId: 0,
showDialog: false,
imgsList: [],
loading: false,
})
const commitApproval = () => {
data.loading = true
let imgs = []
for (let index = 0; index < data.imgsList.length; index++) {
let obj = data.imgsList[index]
imgs.push(obj.url)
}
let params = {
instance_id: data.launchId,
payment_voucher: imgs
}
post(`/api/purchaseOrder/uploadPayment`, params).then((res) => {
ElMessage({ type: 'success', message: '提交成功' })
closeDialog()
context.emit('refresh')
data.loading = false
}).catch(() => {
data.loading = false
})
}
function handleUploadError(err) {
if(JSON.parse(err.message) && JSON.parse(err.message).message) {
ElMessage({ type: 'error', message: JSON.parse(err.message).message })
}
}
function handleRemoveImg(res, ress) {
data.imgsList = ress
}
function handleSuccess(res) {
data.imgsList.push({url: res.data.link})
}
const uploadRef = ref(null)
function clearForm() {
data.imgsList = []
nextTick(() => {
uploadRef.value.clearFiles()
})
}
const closeDialog = () => {
clearForm()
context.emit('close')
data.showDialog = false
}
function handlePreview(File) {
data.dialogImageUrl = File.url
data.picVisible = true
}
watch(() => props, (newProps) => {
if (newProps.show) {
data.showDialog = true
data.launchId = newProps.id
}
}, { deep: true })
return {
uploadRef,
...toRefs(data),
closeDialog,
clearForm,
commitApproval,
handlePreview,
handleSuccess,
handleRemoveImg,
handleUploadError
}
}
}
</script>
<style scoped lang="scss">
</style>

View File

@ -31,10 +31,34 @@ export const whiteList = [
},
{
path: '/purchase/index',
name: 'purchase',
name: 'purchaselist',
full_path: 'views/purchase/index.vue',
component: () => import('views/purchase/index')
},
{
path: '/purchase/supplier',
name: 'purchaseSupplier',
full_path: 'views/purchase/supplier.vue',
component: () => import('views/purchase/supplier')
},
{
path: '/purchase/waitapproval',
name: 'waitapproval',
full_path: 'views/purchase/waitapproval.vue',
component: () => import('views/purchase/waitapproval')
},
{
path: '/purchase/approval',
name: 'purchaseapproval',
full_path: 'views/purchase/approval.vue',
component: () => import('views/purchase/approval')
},
{
path: '/purchase/otherfees',
name: 'otherfees',
full_path: 'views/purchase/otherfees.vue',
component: () => import('views/purchase/otherfees')
},
{
path: '/warehouse/index',
name: 'warehouse',
@ -85,10 +109,14 @@ export const constantRouterComponents = {
'commoditySku': () => import('views/commodity/sku'),
'combination': () => import('views/commodity/combination'),
'commodityBrand': () => import('views/commodity/brand'),
'purchase': () => import('views/purchase/index'),
'purchaselist': () => import('views/purchase/index'),
'warehouse': () => import('views/warehouse/index'),
'warehouseIO': () => import('views/warehouse/io'),
'supplier': () => import('views/supplier/index'),
'purchaseSupplier': () => import('views/purchase/supplier'),
'waitapproval': () => import('views/purchase/waitapproval'),
'purchaseapproval': () => import('views/purchase/approval'),
'otherfees': () => import('views/purchase/otherfees'),
'statistics': () => import('views/statistics/index'),
'role': () => import('views/permission/role'),
'menus': () => import('views/permission/menus'),

View File

@ -158,6 +158,12 @@
<el-radio :label="0">不启用</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="商品成本:">
<el-input placeholder="商品成本" v-model="item.goods_cost" clearable style="width: 250px;"></el-input>
</el-form-item>
<el-form-item label="运费成本:">
<el-input placeholder="运费成本" v-model="item.freight_cost" clearable style="width: 250px;"></el-input>
</el-form-item>
<el-form-item label="赠品:">
<el-radio-group v-model="item.gift" style="width: 250px;">
<el-radio :label="0">不是</el-radio>
@ -373,7 +379,9 @@ export default {
warehouse_id: data.itemInfo.warehouse_id || '',
status: 1,
sort: 0,
gift: 0
gift: 0,
goods_cost: '',
freight_cost: ''
}
data.skusList.push(sku)
}

View File

@ -58,9 +58,11 @@
<el-card shadow="never">
<div class="opaBox">
<el-button type="primary" @click="handleAdd"><el-icon><Plus /></el-icon>&nbsp;新增</el-button>
<!-- <el-button type="warning" @click="handleExport"><span class="iconfont icon-daochu"></span>&nbsp;导出</el-button> -->
<el-button type="primary" v-if="role" :disabled="!chooseList.length" @click="lte_stock = 0, showStock = true">设置预警库存</el-button>
</div>
<el-table :data="tableList" style="width: 100%" border v-loading="loading">
<el-table :data="tableList" style="width: 100%" border v-loading="loading" @select="select"
ref="multipleTable" @select-all="selectAll">
<el-table-column type="selection" width="55" />
<el-table-column prop="id" label="ID" width="80" align="center" />
<el-table-column prop="goods.title" label="商品名称" align="center" />
<el-table-column prop="goods.goods_code" label="商品货号" align="center" />
@ -82,6 +84,9 @@
<el-table-column prop="lock_in_stock" label="运营锁定库存" align="center" />
<el-table-column prop="after_sale_stock" label="售后锁定库存" align="center" />
<el-table-column prop="available_inventory" label="可售库存" align="center" />
<el-table-column prop="lte_stock" label="预警库存" align="center" />
<el-table-column prop="goods_cost" label="商品成本" align="center" />
<el-table-column prop="freight_cost" label="运费成本" align="center" />
<el-table-column prop="warehouse.name" label="仓库" align="center" />
<el-table-column label="状态" align="center">
<template #default="scope">
@ -112,27 +117,31 @@
</div>
</el-card>
<el-dialog v-model="showDialog" width="600px" :title="opaType == 'add' ? '新增' : '编辑' ">
<el-dialog v-model="showUpdate" width="600px" title="新增">
<el-form label-position="right" label-width="110px">
<el-form-item label="所属商品:">
<el-select v-model="itemInfo.goods_id" placeholder="请选择" clearable filterable :disabled="role && opaType == 'edit'">
<el-select v-model="itemInfo.goods_id" placeholder="请选择" clearable filterable disabled>
<el-option v-for="it in goodsList" :key="it.id" :label="it.title" :value="it.id" />
</el-select>
</el-form-item>
<el-form-item label="规格名称:">
<el-input v-model="itemInfo.title" clearable :disabled="role && opaType == 'edit'"></el-input>
<el-input v-model="itemInfo.title" clearable disabled></el-input>
</el-form-item>
<el-form-item label="规格编码:">
<el-input v-model="itemInfo.sku_code" clearable :disabled="role && opaType == 'edit'"></el-input>
<el-input v-model="itemInfo.sku_code" clearable disabled></el-input>
</el-form-item>
<el-form-item label="仓库:">
<el-select v-model="itemInfo.warehouse_id" placeholder="请选择" clearable filterable :disabled="role && opaType == 'edit'">
<el-option v-for="it in warehouseList" :key="it.id" :label="it.name" :value="it.id" />
</el-select>
<el-form-item label="赠品:">
<el-radio-group v-model="itemInfo.gift" disabled>
<el-radio :label="0">不是</el-radio>
<el-radio :label="1"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="总锁定库存:">
<el-input v-model="itemInfo.total_lock_num" disabled></el-input>
</el-form-item>
<el-form-item label="预警库存:">
<el-input v-model="itemInfo.lte_stock" clearable></el-input>
</el-form-item>
<el-form-item label="一阶段库存:">
<el-input v-model="itemInfo.first_stage_stock" clearable></el-input>
</el-form-item>
@ -146,27 +155,64 @@
<el-input v-model="itemInfo.lock_in_stock" clearable></el-input>
</el-form-item>
<el-form-item label="售后锁定库存:">
<el-input v-model="itemInfo.after_sale_stock" clearable :disabled="role && opaType == 'edit'"></el-input>
<el-input v-model="itemInfo.after_sale_stock" clearable disabled></el-input>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="showUpdate = false">取消</el-button>
<el-button type="primary" @click="commitUpdate()" :loading="opa_loading">确定</el-button>
</span>
</template>
</el-dialog>
<el-dialog v-model="showDialog" width="600px" :title="opaType == 'add' ? '新增' : '编辑' ">
<el-form label-position="right" label-width="110px">
<el-form-item label="所属商品:">
<el-select v-model="itemInfo.goods_id" placeholder="请选择" clearable filterable>
<el-option v-for="it in goodsList" :key="it.id" :label="it.title" :value="it.id" />
</el-select>
</el-form-item>
<el-form-item label="规格名称:">
<el-input v-model="itemInfo.title" clearable></el-input>
</el-form-item>
<el-form-item label="规格编码:">
<el-input v-model="itemInfo.sku_code" clearable></el-input>
</el-form-item>
<el-form-item label="仓库:">
<el-select v-model="itemInfo.warehouse_id" placeholder="请选择" clearable filterable>
<el-option v-for="it in warehouseList" :key="it.id" :label="it.name" :value="it.id" />
</el-select>
</el-form-item>
<el-form-item label="售后锁定库存:">
<el-input v-model="itemInfo.after_sale_stock" clearable></el-input>
</el-form-item>
<el-form-item label="商品成本:">
<el-input v-model="itemInfo.goods_cost" clearable></el-input>
</el-form-item>
<el-form-item label="运费成本:">
<el-input v-model="itemInfo.freight_cost" clearable></el-input>
</el-form-item>
<el-form-item label="状态:">
<el-radio-group v-model="itemInfo.status" :disabled="role && opaType == 'edit'">
<el-radio-group v-model="itemInfo.status">
<el-radio :label="1">启用</el-radio>
<el-radio :label="0">不启用</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="赠品:">
<el-radio-group v-model="itemInfo.gift" :disabled="role && opaType == 'edit'">
<el-radio-group v-model="itemInfo.gift">
<el-radio :label="0">不是</el-radio>
<el-radio :label="1"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="排序:">
<el-input-number v-model="itemInfo.sort" :min="0" :disabled="role && opaType == 'edit'" />
<el-input-number v-model="itemInfo.sort" :min="0" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer" v-if="opaType != 'view'">
<span class="dialog-footer">
<el-button @click="showDialog = false">取消</el-button>
<el-button type="primary" @click="commitOpa()" :loading="opa_loading">确定</el-button>
</span>
@ -178,6 +224,19 @@
<img :src="dialogImageUrl" style="max-width: 700px; margin: 0 auto;display: block;" />
</el-dialog>
<el-dialog v-model="showStock" width="600px" title="设置预警库存">
<el-form label-position="right" label-width="110px">
<el-form-item label="预警库存:">
<el-input-number v-model="lte_stock" clearable></el-input-number>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="showStock = false">取消</el-button>
<el-button type="primary" @click="commitStock()">确定</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
@ -209,7 +268,11 @@ export default {
role: localStorage.getItem('roleName') == '爆品运营',
goodsIds: [],
brandIds: [],
brandList: []
brandList: [],
chooseList: [],
lte_stock: 0,
showStock: false,
showUpdate: false
})
function handleSearch() {
@ -260,7 +323,11 @@ export default {
function handleEdit(item) {
data.opaType = 'edit'
data.itemInfo = JSON.parse(JSON.stringify(item))
data.showDialog = true
if(data.role) {
data.showUpdate = true
} else {
data.showDialog = true
}
}
function handleUpload(row) {
@ -292,36 +359,40 @@ export default {
parseErrors(err.response.data.errors)
})
} else {
if(data.role) {
params = {
lock_in_stock: data.itemInfo.lock_in_stock,
first_stage_stock: data.itemInfo.first_stage_stock,
second_stage_stock: data.itemInfo.second_stage_stock,
third_stage_stock: data.itemInfo.third_stage_stock
}
post(`/api/goods/sku/lockInStock/${data.itemInfo.id}`, params, 'PUT').then(() => {
fetchData()
ElMessage({ type: 'success', message: '编辑成功' })
data.showDialog = false
data.opa_loading = false
}).catch((err) => {
data.opa_loading = false
parseErrors(err.response.data.errors)
})
} else {
post(`/api/goods-skus/${data.itemInfo.id}`, params, 'PUT').then(() => {
fetchData()
ElMessage({ type: 'success', message: '编辑成功' })
data.showDialog = false
data.opa_loading = false
}).catch((err) => {
data.opa_loading = false
parseErrors(err.response.data.errors)
})
}
post(`/api/goods-skus/${data.itemInfo.id}`, params, 'PUT').then(() => {
fetchData()
ElMessage({ type: 'success', message: '编辑成功' })
data.showDialog = false
data.opa_loading = false
}).catch((err) => {
data.opa_loading = false
parseErrors(err.response.data.errors)
})
}
}
function commitUpdate() {
data.opa_loading = true
let params = {
lock_in_stock: data.itemInfo.lock_in_stock,
first_stage_stock: data.itemInfo.first_stage_stock,
second_stage_stock: data.itemInfo.second_stage_stock,
third_stage_stock: data.itemInfo.third_stage_stock,
lte_stock: data.itemInfo.lte_stock,
goods_cost: data.itemInfo.goods_cost,
freight_cost: data.itemInfo.freight_cost
}
post(`/api/goods/sku/lockInStock/${data.itemInfo.id}`, params, 'PUT').then(() => {
fetchData()
ElMessage({ type: 'success', message: '编辑成功' })
data.showUpdate = false
data.opa_loading = false
}).catch((err) => {
data.opa_loading = false
parseErrors(err.response.data.errors)
})
}
function getWarehouseList() {
get(`/api/all/warehouses`).then((res) => {
data.warehouseList = res.data
@ -340,6 +411,31 @@ export default {
})
}
function select(e) {
data.chooseList = e
}
function selectAll(e) {
data.chooseList = e
}
function commitStock() {
let ids = []
data.chooseList.forEach((it) => {
ids.push(it.id)
})
let params = {
ids: ids,
lte_stock: data.lte_stock
}
post('/api/goods/sku/batchUpdateLetStock', params, 'PUT').then((res) => {
ElMessage({ type: 'success', message: '操作成功' })
data.chooseList = []
data.showStock = false
fetchData()
})
}
onMounted(() => {
fetchData()
getWarehouseList()
@ -357,9 +453,13 @@ export default {
handleEdit,
handleUpload,
commitOpa,
commitUpdate,
getWarehouseList,
getGoodsList,
getBrandList
getBrandList,
select,
selectAll,
commitStock
}
}
}

View File

@ -0,0 +1,444 @@
<template>
<div class="pageBox">
<div class="searchBox">
<div class="row">
<span class="span">ID</span>
<div class="right"><el-input v-model="filter.id" class="wid100" clearable></el-input></div>
</div>
<div class="row">
<span class="span">供应商名称</span>
<div class="right">
<el-select v-model="filter.purchase_supplier_id" placeholder="请选择" clearable filterable>
<el-option v-for="it in suppliersList" :key="it.id" :label="it.supplier_name" :value="it.id" />
</el-select>
</div>
</div>
<div class="row">
<span class="span">提交时间</span>
<div class="right">
<el-date-picker
v-model="submitTime"
type="datetimerange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD HH:mm:ss"
format="YYYY-MM-DD HH:mm:ss"
style="width: 100%;box-sizing: border-box;">
</el-date-picker>
</div>
</div>
<div class="row">
<span class="span">审批类型</span>
<div class="right">
<el-select v-model="filter.approval_type" placeholder="请选择" clearable class="wid100">
<el-option label="采购订单审批" :value="1" />
<el-option label="预付款打款审批" :value="2" />
<el-option label="尾款打款审批" :value="3" />
<el-option label="已结束" :value="4" />
</el-select>
</div>
</div>
<div class="row row1">
<el-button type="primary" @click="handleSearch"><el-icon><Search /></el-icon>&nbsp;筛选</el-button>
</div>
</div>
<el-card shadow="never">
<div class="opaBox">
<el-button type="primary" @click="handleAdd"><el-icon><Plus /></el-icon>&nbsp;新增</el-button>
</div>
<el-table :data="goodsList" style="width: 100%" border v-loading="loading">
<el-table-column prop="id" label="ID" width="80" align="center" />
<el-table-column prop="type" label="采购类型" align="center">
<template #default="scope">
<span>{{ approvalType[scope.row.approval_type] }}</span>
<div v-if="scope.row.approval_type == 1" :class="'status' + scope.row.order_approval_status">{{ approvalStatus[scope.row.order_approval_status] }}</div>
<div v-else-if="scope.row.approval_type == 2" :class="'status' + scope.row.prepayment_approval_status">{{ approvalStatus[scope.row.prepayment_approval_status] }}</div>
<div v-else-if="scope.row.approval_type == 3" :class="'status' + scope.row.final_payment_approval_status">{{ approvalStatus[scope.row.final_payment_approval_status] }}</div>
</template>
</el-table-column>
<el-table-column prop="purchase_supplier.supplier_name" label="采购供应商" />
<el-table-column label="申请采购商品信息">
<template #default="scope">
<div v-if="scope.row.products">
<div v-for="it in scope.row.products" :key="it.id">{{it.goods && it.goods.title}}{{ it.unit }}</div>
</div>
</template>
</el-table-column>
<el-table-column label="总预计订单金额/总预防款/总尾款" align="center">
<template #default="scope">
<div>{{ scope.row.total_amount }}</div>
<div>{{ scope.row.prepayment_amount }}</div>
<div>{{ scope.row.final_payment_amount }}</div>
</template>
</el-table-column>
<el-table-column label="总实际订单金额/总实际已支付金额/总实际未支付金额" align="center">
<template #default="scope">
<div>{{ scope.row.has_paid_amount }}</div>
<div>{{ scope.row.has_paid_prepayment_amount }}</div>
<div>{{ scope.row.has_paid_final_payment_amount }}</div>
</template>
</el-table-column>
<el-table-column label="提交人/提交时间" align="center">
<template #default="scope">
<div>{{ scope.row.admin_user && scope.row.admin_user.username || '-' }}</div>
<span>{{ scope.row.created_at }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="260">
<template #default="scope">
<div class="elbtn">
<el-button type="primary" v-if="scope.row.approval_type != 4" text @click="resubmit(scope.row.id)"><el-icon><RefreshLeft /></el-icon>重新提审</el-button>
<el-button type="primary" text @click="toPrepayment(scope.row.id)" v-if="(scope.row.approval_type == 1 && scope.row.order_approval_status == 2) || (scope.row.approval_type == 2 && scope.row.prepayment_approval_status == 3)"><el-icon><Position /></el-icon>发起预付款审批</el-button>
<el-button type="primary" text @click="toPayment(scope.row.current_instance_id)"
v-if="(scope.row.approval_type == 2 && scope.row.prepayment_approval_status == 2) || (scope.row.approval_type == 3 && scope.row.final_payment_approval_status == 2)">
<el-icon><Upload /></el-icon>上传支付凭证
</el-button>
<el-button type="primary" text @click="toBalancePayment(scope.row.id)"
v-if="(scope.row.approval_type == 2 && scope.row.prepayment_approval_status == 4) || (scope.row.approval_type == 3 && scope.row.final_payment_approval_status == 3) || (scope.row.approval_type == 3 && scope.row.final_payment_approval_status == 4 && scope.row.total_amount * 1 > scope.row.has_paid_amount * 1)">
<el-icon><Position /></el-icon>尾款打款审批
</el-button>
<el-button type="primary" text @click="toInvoice(scope.row.id)" v-if="scope.row.approval_type != 4"><el-icon><Upload /></el-icon>上传发票</el-button>
<el-button type="danger" text @click="endApproval(scope.row.id)" v-if="scope.row.final_payment_approval_status == 4 && scope.row.approval_type != 4"><el-icon><SwitchButton /></el-icon>结束审批</el-button>
<el-button type="primary" text @click="handleView(scope.row.id)"><el-icon><ZoomIn /></el-icon>查看详情</el-button>
<el-button type="info" text @click="openLogs(scope.row.id)"><el-icon><Clock /></el-icon>审批记录</el-button>
</div>
</template>
</el-table-column>
</el-table>
<div class="page-pagination">
<el-pagination
:current-page="page"
background
layout="prev, pager, next, sizes, total"
:total="total"
:page-sizes="[10, 50, 100]"
:page-size="pageSize"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"></el-pagination>
</div>
</el-card>
<!-- 预览图片 -->
<el-dialog v-model="picVisible" center width="800px">
<img :src="dialogImageUrl" style="max-width: 700px; margin: 0 auto;display: block;" />
</el-dialog>
<el-dialog v-model="showAdd" width="500px" title="新增审批">
<el-form label-position="right" label-width="10px">
<el-form-item label="">
<el-radio-group v-model="add_type">
<el-radio :label="1">采购订单审批</el-radio>
<el-radio :label="2">预付款打款审批</el-radio>
<el-radio :label="3">尾款打款审批</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="showAdd = false">取消</el-button>
<el-button type="primary" @click="curId = 0, showOrderApproval = true, showAdd = false">确定</el-button>
</span>
</template>
</el-dialog>
<!-- 订单审批 -->
<order-approval :show="showOrderApproval" :type="elType" :id="curId" @refresh="handleSearch" @close="showOrderApproval = false"></order-approval>
<!-- 预付款审批 -->
<order-prepayment :show="showPrepayment" :id="curId" @refresh="fetchData" @close="showPrepayment = false"></order-prepayment>
<!-- 上传支付凭证 -->
<upload-payment :show="showPayment" :id="curId" @refresh="fetchData" @close="showPayment = false"></upload-payment>
<!-- 尾款审批 -->
<balance-payment :show="showBalance" :id="curId" @refresh="fetchData" @close="showBalance = false"></balance-payment>
<!-- 修改信息 -->
<update-approval :show="showEditApproval" :id="curId" @refresh="fetchData" @close="showEditApproval = false"></update-approval>
<!-- 修改信息 -->
<approval-logs :show="showApprovalLogs" :id="curId" @close="showApprovalLogs = false"></approval-logs>
<!-- 上传发票 -->
<upload-invoice :show="showInvoice" :id="curId" @close="showInvoice = false"></upload-invoice>
</div>
</template>
<script>
import { onMounted, reactive, toRefs, ref, nextTick } from "vue"
import { get, post } from "@/api/request"
import { Search, Plus, Edit, ZoomIn, Delete, RefreshLeft, SwitchButton, Position, Upload, Clock } from '@element-plus/icons'
import { ElMessage, ElMessageBox } from 'element-plus'
import orderApproval from '@/components/approval/order.vue'
import orderPrepayment from '@/components/approval/prepayment.vue'
import uploadPayment from '@/components/approval/uploadpayment.vue'
import balancePayment from '@/components/approval/balancepayment.vue'
import updateApproval from '@/components/approval/update.vue'
import approvalLogs from '@/components/approval/logs.vue'
import uploadInvoice from '@/components/approval/uploadinvoice.vue'
export default {
components: {
Search, Plus, Edit, ZoomIn, Delete, RefreshLeft, SwitchButton, Position, Upload, Clock,
uploadPayment, balancePayment, updateApproval, orderApproval, orderPrepayment, approvalLogs, uploadInvoice
},
setup() {
const data = reactive({
add_type: 1,
showAdd: false,
showEditApproval: false,
showOrderApproval: false,
showApprovalLogs: false,
showInvoice: false,
showPayment: false,
showBalance: false,
showPrepayment: false,
filter: {},
submitTime: [],
goodsList: [],
page: 1,
pageSize: 10,
total: 0,
loading: false,
picVisible: false,
dialogImageUrl: '',
approvalType: {
'1': '采购订单审批',
'2': '预付款打款审批',
'3': '尾款打款审批',
'4': '已结束'
},
approvalStatus: {
'0': '草稿',
'1': '进行中',
'2': '已完成',
'3': '已驳回',
'4': '上传凭证'
},
warehouseList: [],
suppliersList: [],
allGoodsList: [],
curId: 0,
elType: ''
})
function handleSearch() {
data.page = 1
fetchData()
}
const fetchData = () => {
data.loading = true
let params = {
page: data.page,
pageSize: data.pageSize,
...data.filter,
start_date: data.submitTime ? data.submitTime[0] : '',
end_date: data.submitTime ? data.submitTime[1] : ''
}
get(`/api/purchaseOrder`, params).then((res) => {
data.goodsList = res.data
data.total = res.meta.total
data.loading = false
}).catch(() => {
data.loading = false
})
}
function handleCurrentChange(e) {
data.page = e
fetchData()
}
function handleSizeChange(e) {
data.page = 1
data.pageSize = e
fetchData()
}
function getWarehouseList() {
get(`/api/all/warehouses`).then((res) => {
data.warehouseList = res.data
})
}
function getSuppliersList() {
get(`/api/purchaseSupplier`, {pageSize: 1000}).then((res) => {
data.suppliersList = res.data
})
}
function getAllGoodsList() {
get(`/api/all/goods`).then((res) => {
data.allGoodsList = res.data
})
}
function resubmit(id) {
data.curId = id
data.showEditApproval = true
}
function toPrepayment(id) {
data.curId = id
data.showPrepayment = true
}
function toPayment(id) {
data.curId = id
data.showPayment = true
}
function toBalancePayment(id) {
data.curId = id
data.showBalance = true
}
function openLogs(id) {
data.curId = id
data.showApprovalLogs = true
}
function toInvoice(id) {
data.curId = id
data.showInvoice = true
}
function endApproval(id) {
ElMessageBox.confirm('确定要结束当前审批流程吗?', '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
post(`/api/purchaseOrder/endProcess`, {purchase_order_id: id}).then(() => {
fetchData()
ElMessage({ type: 'success', message: '操作成功' })
})
})
}
function handleAdd() {
data.elType = ''
data.curId = 0
data.showOrderApproval = true
}
function handleView(id) {
data.elType = 'view'
data.curId = id
data.showOrderApproval = true
}
onMounted(() => {
fetchData()
getWarehouseList()
getSuppliersList()
getAllGoodsList()
})
return {
...toRefs(data),
handleAdd,
handleSearch,
handleCurrentChange,
handleSizeChange,
fetchData,
getWarehouseList,
getSuppliersList,
getAllGoodsList,
resubmit,
endApproval,
toPrepayment,
toPayment,
toBalancePayment,
openLogs,
toInvoice,
handleView
}
}
}
</script>
<style lang="scss" scoped>
.searchBox{
display: flex;
flex-wrap: wrap;
background-color: #fff;
padding: 15px 15px 0 0;
border-radius: 4px;
margin-bottom: 15px;
.row{
display: flex;
align-items: center;
width: 20%;
box-sizing: border-box;
margin-bottom: 15px;
.span{
display: block;
width: 100px;
font-size: 14px;
text-align: right;
box-sizing: border-box;
}
.right{
width: calc(100% - 100px);
}
.wid100{
width: 100%;
}
&.row1{
margin-left: 15px;
width: auto;
}
}
}
.opaBox{
margin-bottom: 15px;
}
.imgBox{
display: flex;
flex-wrap: wrap;
.el-image{
width: 60px;
height: 60px;
border-radius: 4px;
margin-right: 10px;
}
}
.skuBox{
border: 1px solid #e5e5e5;
border-radius: 5px;
padding: 15px 0;
margin-bottom: 15px;
background-color: #f3f3f3;
.tit{
padding-left: 40px;
font-weight: 600;
font-size: 15px;
margin-bottom: 15px;
}
}
::v-deep .elbtn .el-button.is-text{
padding: 8px 0px;
}
.status1{
color: #f90;
}
.status2{
color: #67C23A;
}
.status3{
color: #909399;
}
.status4{
color: #F56C6C;
}
</style>

View File

@ -343,31 +343,31 @@ export default {
}
function handleFileSuccess(res, ress) {
if (res.code === 0) {
data.qaFileList = [{ name: ress.name, url: res.data.link }]
}
}
function handleFileRemove(res, ress) {
data.qaFileList = ress
if (res.code === 0) {
data.qaFileList = [{ name: ress.name, url: res.data.link }]
}
}
function handleFileRemove(res, ress) {
data.qaFileList = ress
}
function previewFile(File) {
window.open(File.response.data.link)
}
const handleBeforeUpload = (file) => {
let type = file.name.indexOf('.pdf') !== -1 || file.name.indexOf('.doc') !== -1 || file.name.indexOf('.docx') !== -1 || file.name.indexOf('.zip') !== -1 || file.name.indexOf('.xlsx') !== -1
if (type) {
const isLt4M = file.size / 1024 / 1024 < 4
if (!isLt4M) {
ElMessage.error('附件上传大小不能超过 4MB!')
return false
}
} else {
ElMessage.error('上传文件格式不正确')
function previewFile(File) {
window.open(File.response.data.link)
}
const handleBeforeUpload = (file) => {
let type = file.name.indexOf('.pdf') !== -1 || file.name.indexOf('.doc') !== -1 || file.name.indexOf('.docx') !== -1 || file.name.indexOf('.zip') !== -1 || file.name.indexOf('.xlsx') !== -1
if (type) {
const isLt4M = file.size / 1024 / 1024 < 4
if (!isLt4M) {
ElMessage.error('附件上传大小不能超过 4MB!')
return false
}
} else {
ElMessage.error('上传文件格式不正确')
return false
}
}
function handleSkuDelete(index) {
data.skusList.splice(index, 1)

View File

@ -0,0 +1,265 @@
<template>
<div class="pageBox">
<div class="searchBox">
<div class="row">
<span class="span">开户信息名称</span>
<div class="right"><el-input v-model="filter.name" class="wid100" clearable></el-input></div>
</div>
<div class="row">
<span class="span">银行开户名</span>
<div class="right"><el-input v-model="filter.bank_account_holder" class="wid100" clearable></el-input></div>
</div>
<div class="row">
<el-button type="primary" @click="handleSearch"><el-icon><Search /></el-icon>&nbsp;筛选</el-button>
</div>
</div>
<el-card shadow="never">
<div class="opaBox">
<el-button type="primary" @click="handleAdd"><el-icon><Plus /></el-icon>&nbsp;新增</el-button>
</div>
<el-table :data="goodsList" style="width: 100%" border v-loading="loading">
<el-table-column prop="id" label="ID" width="80" align="center" />
<el-table-column prop="name" label="开户信息名称" />
<el-table-column prop="bank_account_name" label="银行开户名" />
<el-table-column prop="bank_account_number" label="银行帐户" />
<el-table-column prop="bank_name" label="开户银行支行名称" />
<el-table-column label="操作" align="center" width="150">
<template #default="scope">
<el-button type="primary" circle @click="handleEdit(scope.row)"><el-icon><Edit /></el-icon></el-button>
</template>
</el-table-column>
</el-table>
<div class="page-pagination">
<el-pagination
:current-page="page"
background
layout="prev, pager, next, sizes, total"
:total="total"
:page-sizes="[10, 50, 100]"
:page-size="pageSize"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"></el-pagination>
</div>
</el-card>
<el-dialog v-model="showDialog" width="900px" :title="opaType == 'add' ? '新增' : '编辑' ">
<el-form label-position="right" label-width="170px">
<el-form-item label="开户信息名称:">
<el-input v-model="itemInfo.name" clearable></el-input>
</el-form-item>
<el-form-item label="银行开户名:">
<el-input v-model="itemInfo.bank_account_name" clearable placeholder="请输入银行开户名"></el-input>
</el-form-item>
<el-form-item label="银行账户:">
<el-input v-model="itemInfo.bank_account_number" clearable placeholder="请输入银行账户"></el-input>
</el-form-item>
<el-form-item label="开户银行支行名称:">
<el-input v-model="itemInfo.bank_name" clearable placeholder="请输入银行开户名"></el-input>
</el-form-item>
<el-form-item label="开户银行所在地地址:">
<el-input v-model="itemInfo.bank_address" clearable placeholder="请输入开户银行所在地地址"></el-input>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="showDialog = false">取消</el-button>
<el-button type="primary" @click="commitSupplier()" :loading="opa_loading">确定</el-button>
</span>
</template>
</el-dialog>
<!-- 预览图片 -->
<el-dialog v-model="picVisible" center width="800px">
<img :src="dialogImageUrl" style="max-width: 700px; margin: 0 auto;display: block;" />
</el-dialog>
</div>
</template>
<script>
import { onMounted, reactive, toRefs } from "vue"
import { get, post } from "@/api/request"
import { Search, Plus, Edit } from '@element-plus/icons'
import { ElMessage } from 'element-plus'
import { parseErrors } from 'components/common'
export default {
components: {
Search, Plus, Edit
},
setup() {
const data = reactive({
filter: {},
goodsList: [],
page: 1,
pageSize: 10,
total: 0,
loading: false,
opaType: '',
showDialog: false,
opa_loading: false,
itemInfo: {},
supplier_name: '',
bank_account_holder: ''
})
function handleSearch() {
data.page = 1
fetchData()
}
const fetchData = () => {
data.loading = true
let params = {
page: data.page,
pageSize: data.pageSize,
...data.filter
}
get(`/api/otherExpenseAccount`, params).then((res) => {
data.goodsList = res.data
data.total = res.meta.total
data.loading = false
}).catch(() => {
data.loading = false
})
}
function handleCurrentChange(e) {
data.page = e
fetchData()
}
function handleSizeChange(e) {
data.page = 1
data.pageSize = e
fetchData()
}
function handleAdd() {
data.opaType = 'add'
data.itemInfo = {}
data.showDialog = true
}
function handleEdit(item) {
data.opaType = 'edit'
data.itemInfo = JSON.parse(JSON.stringify(item))
data.showDialog = true
}
function commitSupplier() {
if(!data.itemInfo.name) {
return ElMessage.info('请输入开户信息名称')
} else if(!data.itemInfo.bank_account_name) {
return ElMessage.info('银行开户名必填')
} else if(!data.itemInfo.bank_account_number) {
return ElMessage.info('银行账户必填')
}
data.opa_loading = true
let params = {
...data.itemInfo
}
if(data.opaType == 'add') {
post(`/api/otherExpenseAccount`, params).then(() => {
data.page = 1
fetchData()
ElMessage({ type: 'success', message: '新增成功' })
data.showDialog = false
data.opa_loading = false
}).catch((err) => {
data.opa_loading = false
parseErrors(err.response.data.errors)
})
} else {
post(`/api/purchaseSupplier/${data.itemInfo.id}`, params, 'PUT').then(() => {
fetchData()
ElMessage({ type: 'success', message: '编辑成功' })
data.showDialog = false
data.opa_loading = false
}).catch((err) => {
data.opa_loading = false
parseErrors(err.response.data.errors)
})
}
}
onMounted(() => {
fetchData()
})
return {
...toRefs(data),
handleSearch,
handleCurrentChange,
handleSizeChange,
fetchData,
handleAdd,
handleEdit,
commitSupplier
}
}
}
</script>
<style lang="scss" scoped>
.searchBox{
display: flex;
flex-wrap: wrap;
background-color: #fff;
padding: 15px 0 0 0;
border-radius: 4px;
margin-bottom: 15px;
.row{
display: flex;
align-items: center;
width: 20%;
box-sizing: border-box;
margin-bottom: 15px;
&.row1{
width: 25%;
}
.span{
display: block;
width: 100px;
font-size: 14px;
text-align: right;
box-sizing: border-box;
}
.right{
width: calc(100% - 120px);
}
.wid100{
width: 100%;
}
}
}
.opaBox{
margin-bottom: 15px;
}
.imgBox{
display: flex;
flex-wrap: wrap;
.el-image{
width: 60px;
height: 60px;
border-radius: 4px;
margin-right: 10px;
}
}
.skuBox{
border: 1px solid #e5e5e5;
border-radius: 5px;
padding: 15px 0;
margin-bottom: 15px;
background-color: #f3f3f3;
.tit{
padding-left: 40px;
font-weight: 600;
font-size: 15px;
margin-bottom: 15px;
}
}
</style>

View File

@ -0,0 +1,447 @@
<template>
<div class="pageBox">
<div class="searchBox">
<div class="row">
<span class="span">供应商名称</span>
<div class="right"><el-input v-model="supplier_name" class="wid100" clearable></el-input></div>
</div>
<div class="row">
<el-button type="primary" @click="handleSearch"><el-icon><Search /></el-icon>&nbsp;筛选</el-button>
</div>
</div>
<el-card shadow="never">
<div class="opaBox">
<el-button type="primary" @click="handleAdd"><el-icon><Plus /></el-icon>&nbsp;新增</el-button>
<!-- <el-button type="warning" @click="handleExport"><span class="iconfont icon-daochu"></span>&nbsp;导出</el-button> -->
</div>
<el-table :data="goodsList" style="width: 100%" border v-loading="loading">
<el-table-column prop="id" label="ID" width="80" align="center" />
<el-table-column prop="supplier_name" label="供应商名称" />
<el-table-column label="营业执照" align="center">
<template #default="scope">
<div class="imgBox" v-if="scope.row.business_license_path">
<el-image :z-index="9999" :src="scope.row.business_license_path" :hide-on-click-modal="true" :preview-src-list="[scope.row.business_license_path]" fit="cover" :preview-teleported="true" />
</div>
</template>
</el-table-column>
<el-table-column label="生产许可证" align="center">
<template #default="scope">
<div class="imgBox" v-if="scope.row.production_license_path">
<el-image :z-index="9999" :src="scope.row.production_license_path" :hide-on-click-modal="true" :preview-src-list="[scope.row.production_license_path]" fit="cover" :preview-teleported="true" />
</div>
</template>
</el-table-column>
<el-table-column label="合同">
<template #default="scope">
<div class="imgBox" v-if="scope.row.contract_path">
<a :href="scope.row.contract_path" target="_blank">合同附件</a>
</div>
</template>
</el-table-column>
<el-table-column prop="bank_account" label="银行帐户" />
<el-table-column prop="bank_account_holder" label="银行开户名" />
<el-table-column prop="bank_branch_name" label="开户银行支行名称" />
<el-table-column label="操作" align="center" width="150">
<template #default="scope">
<el-button type="primary" circle @click="handleEdit(scope.row)"><el-icon><Edit /></el-icon></el-button>
</template>
</el-table-column>
</el-table>
<div class="page-pagination">
<el-pagination
:current-page="page"
background
layout="prev, pager, next, sizes, total"
:total="total"
:page-sizes="[10, 50, 100]"
:page-size="pageSize"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"></el-pagination>
</div>
</el-card>
<el-dialog v-model="showDialog" width="900px" :title="opaType == 'add' ? '新增' : '编辑' ">
<el-form label-position="right" label-width="150px">
<el-form-item label="供应商名称:">
<el-input v-model="itemInfo.supplier_name" clearable></el-input>
</el-form-item>
<el-form-item label="营业执照:">
<el-upload
ref="yyzzRef"
action="/api/upload/img"
:headers="headers"
:on-remove="handleRemoveYyzzImg"
:on-error="handleUploadError"
:on-preview="handlePreview"
:on-success="handleYyzzSuccess"
:file-list="yyzzList"
:show-file-list="true"
list-type="picture-card"
accept=".png,.jpg,.gif">
<el-icon><Plus /></el-icon>
</el-upload>
</el-form-item>
<el-form-item label="生产许可证:">
<el-upload
ref="xkzRef"
action="/api/upload/img"
:headers="headers"
:on-remove="handleRemoveXkzImg"
:on-error="handleUploadError"
:on-preview="handlePreview"
:on-success="handleXkzSuccess"
:file-list="xkzList"
:show-file-list="true"
list-type="picture-card"
accept=".png,.jpg,.gif">
<el-icon><Plus /></el-icon>
</el-upload>
</el-form-item>
<el-form-item label="合同:">
<el-upload
ref="fileRef"
action="/api/upload/file"
:on-success="handleFileSuccess"
:on-remove="handleFileRemove"
:before-upload="handleBeforeUpload"
:on-error="handleUploadError"
:on-preview="previewFile"
:headers="headers"
:file-list="fileList"
:show-file-list="true">
<el-button type="primary">上传附件</el-button>
<template #tip>
<div class="el-upload__tip">请上传zippdfexceldocdocx格式附件最大限制为 4 M</div>
</template>
</el-upload>
</el-form-item>
<el-form-item label="银行帐户:">
<el-input v-model="itemInfo.bank_account" clearable placeholder="请输入银行账户"></el-input>
<div style="color: #f00;font-size: 12px;">请仔细核对银行账户</div>
</el-form-item>
<el-form-item label="银行开户名:">
<el-input v-model="itemInfo.bank_account_holder" clearable placeholder="请输入银行开户名"></el-input>
</el-form-item>
<el-form-item label="开户银行支行名称:">
<el-input v-model="itemInfo.bank_branch_name" clearable placeholder="请输入银行开户名"></el-input>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="showDialog = false">取消</el-button>
<el-button type="primary" @click="commitSupplier()" :loading="opa_loading">确定</el-button>
</span>
</template>
</el-dialog>
<!-- 预览图片 -->
<el-dialog v-model="picVisible" center width="800px">
<img :src="dialogImageUrl" style="max-width: 700px; margin: 0 auto;display: block;" />
</el-dialog>
</div>
</template>
<script>
import { onMounted, reactive, toRefs, ref, nextTick } from "vue"
import { get, post } from "@/api/request"
import { Search, Plus, Edit, ZoomIn, Delete } from '@element-plus/icons'
import { ElMessage, ElMessageBox } from 'element-plus'
import { parseErrors } from 'components/common'
export default {
components: {
Search, Plus, Edit, ZoomIn, Delete
},
setup() {
const data = reactive({
headers: {
Authorization: localStorage.getItem('token'),
'Shop-Id': localStorage.getItem('shopId') || ''
},
supplier_name: '',
goodsList: [],
page: 1,
pageSize: 10,
total: 0,
loading: false,
opaType: '',
showDialog: false,
opa_loading: false,
Type: {
'default': '默认'
},
itemInfo: {},
picVisible: false,
dialogImageUrl: '',
fileList: [],
yyzzList: [],
xkzList: [],
})
function handleSearch() {
data.page = 1
fetchData()
}
const fetchData = () => {
data.loading = true
let params = {
page: data.page,
pageSize: data.pageSize,
supplier_name: data.supplier_name
}
get(`/api/purchaseSupplier`, params).then((res) => {
data.goodsList = res.data
data.total = res.meta.total
data.loading = false
}).catch(() => {
data.loading = false
})
}
function handleCurrentChange(e) {
data.page = e
fetchData()
}
function handleSizeChange(e) {
data.page = 1
data.pageSize = e
fetchData()
}
function handleAdd() {
data.opaType = 'add'
data.itemInfo = {
type: 'default',
sort: 0,
status: 1
}
data.showDialog = true
}
function handleEdit(item) {
data.opaType = 'edit'
data.itemInfo = JSON.parse(JSON.stringify(item))
data.yyzzList = item.business_license_path ? [{url: item.business_license_path}] : []
data.xkzList = item.production_license_path ? [{url: item.production_license_path}] : []
data.fileList = item.contract_path ? [{name: '合同附件', url: item.contract_path}] : []
data.showDialog = true
}
function commitSupplier() {
if(!data.itemInfo.supplier_name) {
return ElMessage.info('请输入供应商名称')
} else if(!data.yyzzList.length) {
return ElMessage.info('请上传营业执照')
} else if(!data.fileList.length) {
return ElMessage.info('请上传合同附件')
} else if(!data.itemInfo.bank_account) {
return ElMessage.info('请输入银行账户')
} else if(!data.itemInfo.bank_account_holder) {
return ElMessage.info('请输入银行开户名')
} else if(!data.itemInfo.bank_branch_name) {
return ElMessage.info('请输入银行开户名')
}
data.opa_loading = true
let params = {
supplier_name: data.itemInfo.supplier_name,
business_license_path: data.yyzzList[0].url,
production_license_path: data.xkzList[0] && data.xkzList[0].url || '',
contract_path: data.fileList[0].url,
bank_account: data.itemInfo.bank_account,
bank_account_holder: data.itemInfo.bank_account_holder,
bank_branch_name: data.itemInfo.bank_branch_name
}
if(data.opaType == 'add') {
post(`/api/purchaseSupplier`, params).then(() => {
clearForm()
data.page = 1
fetchData()
ElMessage({ type: 'success', message: '新增成功' })
data.showDialog = false
data.opa_loading = false
}).catch((err) => {
data.opa_loading = false
parseErrors(err.response.data.errors)
})
} else {
post(`/api/purchaseSupplier/${data.itemInfo.id}`, params, 'PUT').then(() => {
clearForm()
fetchData()
ElMessage({ type: 'success', message: '编辑成功' })
data.showDialog = false
data.opa_loading = false
}).catch((err) => {
data.opa_loading = false
parseErrors(err.response.data.errors)
})
}
}
function handleRemoveYyzzImg(res, ress) {
data.yyzzList = []
}
function handleRemoveXkzImg(res, ress) {
data.xkzList = []
}
function handleUploadError(err) {
if(JSON.parse(err.message) && JSON.parse(err.message).message) {
ElMessage({ type: 'error', message: JSON.parse(err.message).message })
}
}
function handleYyzzSuccess(res) {
data.yyzzList = [{url: res.data.link}]
}
function handleXkzSuccess(res) {
data.xkzList = [{url: res.data.link}]
}
function handlePreview(File) {
data.dialogImageUrl = File.url
data.picVisible = true
}
function handleFileSuccess(res, ress) {
if (res.code === 0) {
data.fileList = [{ name: ress.name, url: res.data.link }]
}
}
function handleFileRemove(res, ress) {
data.fileList = ress
}
function previewFile(File) {
window.open(File.url || File.response.data.link)
}
const handleBeforeUpload = (file) => {
let type = file.name.indexOf('.pdf') !== -1 || file.name.indexOf('.doc') !== -1 || file.name.indexOf('.docx') !== -1 || file.name.indexOf('.zip') !== -1 || file.name.indexOf('.xlsx') !== -1
if (type) {
const isLt4M = file.size / 1024 / 1024 < 4
if (!isLt4M) {
ElMessage.error('附件上传大小不能超过 4MB!')
return false
}
} else {
ElMessage.error('上传文件格式不正确')
return false
}
}
const yyzzRef = ref(null)
const xkzRef = ref(null)
const fileRef = ref(null)
function clearForm() {
data.yyzzList = []
data.xkzList = []
data.fileList = []
nextTick(() => {
yyzzRef.value.clearFiles()
xkzRef.value.clearFiles()
fileRef.value.clearFiles()
})
}
onMounted(() => {
fetchData()
})
return {
yyzzRef,
xkzRef,
fileRef,
parseErrors,
...toRefs(data),
handleSearch,
handleCurrentChange,
handleSizeChange,
fetchData,
handleAdd,
handleEdit,
commitSupplier,
handleRemoveYyzzImg,
handleRemoveXkzImg,
handleUploadError,
handlePreview,
handleYyzzSuccess,
handleXkzSuccess,
handleFileSuccess,
handleFileRemove,
previewFile,
handleBeforeUpload,
clearForm
}
}
}
</script>
<style lang="scss" scoped>
.searchBox{
display: flex;
flex-wrap: wrap;
background-color: #fff;
padding: 15px 0 0 0;
border-radius: 4px;
margin-bottom: 15px;
.row{
display: flex;
align-items: center;
width: 20%;
box-sizing: border-box;
margin-bottom: 15px;
&.row1{
width: 25%;
}
.span{
display: block;
width: 100px;
font-size: 14px;
text-align: right;
box-sizing: border-box;
}
.right{
width: calc(100% - 120px);
}
.wid100{
width: 100%;
}
}
}
.opaBox{
margin-bottom: 15px;
}
.imgBox{
display: flex;
flex-wrap: wrap;
.el-image{
width: 60px;
height: 60px;
border-radius: 4px;
margin-right: 10px;
}
}
.skuBox{
border: 1px solid #e5e5e5;
border-radius: 5px;
padding: 15px 0;
margin-bottom: 15px;
background-color: #f3f3f3;
.tit{
padding-left: 40px;
font-weight: 600;
font-size: 15px;
margin-bottom: 15px;
}
}
</style>

View File

@ -0,0 +1,319 @@
<template>
<div class="pageBox">
<div class="searchBox">
<div class="row">
<span class="span">ID</span>
<div class="right"><el-input v-model="filter.id" class="wid100" clearable></el-input></div>
</div>
<div class="row">
<span class="span">提交时间</span>
<div class="right">
<el-date-picker
v-model="submitTime"
type="datetimerange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD HH:mm:ss"
format="YYYY-MM-DD HH:mm:ss"
style="width: 100%;box-sizing: border-box;">
</el-date-picker>
</div>
</div>
<div class="row">
<span class="span">审批类型</span>
<div class="right">
<el-select v-model="filter.type" placeholder="请选择" clearable class="wid100">
<el-option label="采购订单审批" :value="1" />
<el-option label="预付款打款审批" :value="2" />
<el-option label="尾款打款审批" :value="3" />
</el-select>
</div>
</div>
<div class="row row1">
<el-button type="primary" @click="handleSearch"><el-icon><Search /></el-icon>&nbsp;筛选</el-button>
</div>
</div>
<el-card shadow="never">
<div class="opaBox">
<el-button type="primary" @click="showAdd = true"><el-icon><Plus /></el-icon>&nbsp;新增</el-button>
</div>
<el-table :data="goodsList" style="width: 100%" border v-loading="loading">
<el-table-column prop="id" label="ID" width="80" align="center" />
<el-table-column prop="type" label="采购类型" align="center">
<template #default="scope">
<span>{{ approvalType[scope.row.order.approval_type] }}</span>
<div v-if="scope.row.order.approval_type == 1">{{ approvalStatus[scope.row.order.order_approval_status] }}</div>
<div v-else-if="scope.row.order.approval_type == 2">{{ approvalStatus[scope.row.order.prepayment_approval_status] }}</div>
<div v-else-if="scope.row.order.approval_type == 3">{{ approvalStatus[scope.row.order.final_payment_approval_status] }}</div>
</template>
</el-table-column>
<el-table-column label="总预计订单金额/总预防款/总尾款" align="center">
<template #default="scope">
<div>{{ scope.row.order.total_amount }}</div>
<div>{{ scope.row.order.prepayment_amount }}</div>
<div>{{ scope.row.order.final_payment_amount }}</div>
</template>
</el-table-column>
<el-table-column label="总实际订单金额/总实际已支付金额/总实际未支付金额" align="center">
<template #default="scope">
<div v-if="scope.row.order">
<div>{{ scope.row.order.has_paid_amount }}</div>
<div>{{ scope.row.order.has_paid_prepayment_amount }}</div>
<div>{{ scope.row.order.has_paid_final_payment_amount }}</div>
</div>
</template>
</el-table-column>
<el-table-column label="提交人/提交时间" align="center">
<template #default="scope">
<div>{{ scope.row.admin_user && scope.row.admin_user.username || '-' }}</div>
<span>{{ scope.row.created_at }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="200">
<template #default="scope">
<el-button type="primary" text @click="toApproval(scope.row.id)"><el-icon><Stamp /></el-icon>审批</el-button>
</template>
</el-table-column>
</el-table>
<div class="page-pagination">
<el-pagination
:current-page="page"
background
layout="prev, pager, next, sizes, total"
:total="total"
:page-sizes="[10, 50, 100]"
:page-size="pageSize"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"></el-pagination>
</div>
</el-card>
<el-dialog v-model="showDialog" width="500px" title="审批">
<el-form label-position="right" label-width="100px">
<el-form-item label="审批状态:">
<el-radio-group v-model="spInfo.status">
<el-radio :label="2">通过</el-radio>
<el-radio :label="3">驳回</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="备注:">
<el-input v-model="spInfo.comment" type="textarea" :rows="4"></el-input>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="showDialog = false">取消</el-button>
<el-button type="primary" @click="commitApproval()">确定</el-button>
</span>
</template>
</el-dialog>
<order-approval :show="showOrderApproval" :id="curId" @refresh="handleSearch" @close="showOrderApproval = false"></order-approval>
</div>
</template>
<script>
import { onMounted, reactive, toRefs, ref, nextTick } from "vue"
import { get, post } from "@/api/request"
import { Search, Plus, Edit, ZoomIn, Delete, Stamp } from '@element-plus/icons'
import { ElMessage, ElMessageBox } from 'element-plus'
import orderApproval from '@/components/approval/order.vue'
export default {
components: {
Search, Plus, Edit, ZoomIn, Delete, orderApproval, Stamp
},
setup() {
const data = reactive({
add_type: 1,
showDialog: false,
showOrderApproval: false,
filter: {},
submitTime: [],
goodsList: [],
page: 1,
pageSize: 10,
total: 0,
loading: false,
picVisible: false,
dialogImageUrl: '',
approvalType: {
'1': '采购订单审批',
'2': '预付款打款审批',
'3': '尾款打款审批',
'4': '已结束'
},
approvalStatus: {
'0': '草稿',
'1': '进行中',
'2': '已完成',
'3': '已取消'
},
warehouseList: [],
suppliersList: [],
allGoodsList: [],
curId: 0,
spInfo: {}
})
function handleSearch() {
data.page = 1
fetchData()
}
const fetchData = () => {
data.loading = true
let params = {
page: data.page,
pageSize: data.pageSize,
...data.filter,
wait_type: 1,
start_time: data.submitTime ? data.submitTime[0] : '',
end_time: data.submitTime ? data.submitTime[1] : ''
}
get(`/api/purchaseOrder/instanceList`, params).then((res) => {
data.goodsList = res.data
data.total = res.meta.total
data.loading = false
}).catch(() => {
data.loading = false
})
}
function handleCurrentChange(e) {
data.page = e
fetchData()
}
function handleSizeChange(e) {
data.page = 1
data.pageSize = e
fetchData()
}
function getWarehouseList() {
get(`/api/all/warehouses`).then((res) => {
data.warehouseList = res.data
})
}
function getSuppliersList() {
get(`/api/suppliers`, {pageSize: 1000}).then((res) => {
data.suppliersList = res.data
})
}
function getAllGoodsList() {
get(`/api/all/goods`).then((res) => {
data.allGoodsList = res.data
})
}
function toApproval(id) {
data.curId = id
data.spInfo = {
status: 2,
comment: ''
}
data.showDialog = true
}
function commitApproval() {
let params = {
instance_id: data.curId,
status: data.spInfo.status,
comment: data.spInfo.comment
}
post(`/api/purchaseOrder/processApproval`, params).then((res) => {
ElMessage.success('审批成功')
data.showDialog = false
fetchData()
})
}
onMounted(() => {
fetchData()
getWarehouseList()
getSuppliersList()
getAllGoodsList()
})
return {
...toRefs(data),
handleSearch,
handleCurrentChange,
handleSizeChange,
fetchData,
getWarehouseList,
getSuppliersList,
getAllGoodsList,
toApproval,
commitApproval
}
}
}
</script>
<style lang="scss" scoped>
.searchBox{
display: flex;
flex-wrap: wrap;
background-color: #fff;
padding: 15px 15px 0 0;
border-radius: 4px;
margin-bottom: 15px;
.row{
display: flex;
align-items: center;
width: 20%;
box-sizing: border-box;
margin-bottom: 15px;
.span{
display: block;
width: 100px;
font-size: 14px;
text-align: right;
box-sizing: border-box;
}
.right{
width: calc(100% - 100px);
}
.wid100{
width: 100%;
}
&.row1{
margin-left: 15px;
}
}
}
.opaBox{
margin-bottom: 15px;
}
.imgBox{
display: flex;
flex-wrap: wrap;
.el-image{
width: 60px;
height: 60px;
border-radius: 4px;
margin-right: 10px;
}
}
.skuBox{
border: 1px solid #e5e5e5;
border-radius: 5px;
padding: 15px 0;
margin-bottom: 15px;
background-color: #f3f3f3;
.tit{
padding-left: 40px;
font-weight: 600;
font-size: 15px;
margin-bottom: 15px;
}
}
</style>

View File

@ -48,6 +48,9 @@
</div>
</div>
<el-card shadow="never">
<div class="opaBox">
<el-button type="warning" @click="handleExport" :loading="exportLoading"><span class="iconfont icon-daochu"></span>&nbsp;导出</el-button>
</div>
<el-table :data="statisticsList" style="width: 100%" border v-loading="loading" @sort-change="sortChange"
:default-sort="{
prop: 'number,order_num,seven_day_avg_number,stock_wait,three_day_avg_number,three_day_stock_wait,thirty_day_number,actual_inventory,total_profit',
@ -86,6 +89,8 @@
<div v-if="scope.row.goods_sku">{{ scope.row.goods_sku.actual_inventory }}{{ scope.row.goods_sku.lock_in_stock }}</div>
</template>
</el-table-column>
<el-table-column prop="goods_cost" label="商品成本" align="center" />
<el-table-column prop="freight_cost" label="运费成本" align="center" />
<el-table-column prop="refund_amount" label="退款金额" align="center" />
<el-table-column prop="red_refund_amount" label="红包退款有责金额" align="center" />
<el-table-column prop="total_profit" label="总利润" align="center" />
@ -241,6 +246,7 @@ import { onMounted, reactive, toRefs } from "vue"
import { get } from "@/api/request"
import { Search, Shop, TrendCharts, QuestionFilled, List } from '@element-plus/icons'
import * as echarts from 'echarts'
import { ElMessage } from 'element-plus'
import dayjs from 'dayjs'
export default {
@ -283,7 +289,8 @@ export default {
from_shop_ids: [],
shopsList: [],
grain_size: 60,
dataLineY2: []
dataLineY2: [],
exportLoading: false
})
function handleSearch() {
@ -559,6 +566,48 @@ export default {
})
}
const handleExport = () => {
data.exportLoading = true
let params = {
...data.filter,
page: data.page,
pageSize: data.pageSize,
start_date: data.rangeTime ? data.rangeTime[0] : '',
end_date: data.rangeTime ? data.rangeTime[1] : '',
direction: data.ascOrDesc,
order_by_column: data.sort,
export: 1
}
params.brand_id = data.filter.brand_id || 0
get(`/api/orderItemDailyReport`, params, 'blob').then((res) => {
downLoadXls(res)
ElMessage({ type: "success", message: "导出成功!" })
data.exportLoading = false
}).catch(() => {
data.exportLoading = false
})
}
function downLoadXls(response) {
const content = response
const blob = new Blob([content])
const fileName = `数据统计.xlsx`
if ('download' in document.createElement('a')) {
// IE
const elink = document.createElement('a')
elink.download = fileName
elink.style.display = 'none'
elink.href = URL.createObjectURL(blob)
document.body.appendChild(elink)
elink.click()
URL.revokeObjectURL(elink.href) // URL
document.body.removeChild(elink)
} else {
// IE10+
navigator.msSaveBlob(blob, fileName)
}
}
onMounted(() => {
fetchData()
getBrandList()
@ -582,7 +631,8 @@ export default {
orderCharts,
getOrderCharts,
changeOrderTime,
getShopsList
getShopsList,
handleExport
}
}
}
@ -618,6 +668,9 @@ export default {
}
}
}
.opaBox{
margin-bottom: 15px;
}
.imgBox{
.el-image{
width: 60px;

View File

@ -21,8 +21,9 @@ module.exports = {
// target: "http://192.168.0.52:86", // 本地
// target: "http://192.168.99.5:8093", // 本地
// target: "http://43.138.23.240:82", // 本地//
// target: "http://192.168.99.72:81", // 本地//
// target: "http://192.168.202.67:86", // 本地//
target: 'http://warehouse.chutang66.com/',
// target: 'http://world.dev.chutang66.com/',
changeOrigin: true, //开启代理
pathRewrite: { // 重命名
"^/api": "api"