myERP/src/views/purchase/index.vue

528 lines
16 KiB
Vue
Raw Normal View History

2025-06-14 10:30:10 +08:00
<template>
<div class="pageBox">
<!-- <div class="searchBox">
<div class="row">
<span class="span">商品名称</span>
<div class="right"><el-input v-model="goods_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="type" label="采购类型" align="center">
<template #default="scope">
<span>{{ Type[scope.row.type] }}</span>
</template>
</el-table-column>
<el-table-column prop="supplier.name" label="供应商" align="center" />
<el-table-column prop="warehouse.name" label="仓库" align="center" />
<el-table-column prop="batch_number" label="批次" align="center" />
<el-table-column label="采购单" align="center" min-width="150">
<template #default="scope">
<div class="imgBox">
<el-image :z-index="9999" v-for="(item, index) in scope.row.images" :key="index" :src="item" :hide-on-click-modal="true" :preview-src-list="[item]" fit="cover" :preview-teleported="true" />
</div>
</template>
</el-table-column>
<el-table-column prop="attachments" label="附件">
<template #default="scope">
<div class="imgBox">
<a :href="scope.row.attachments" target="_blank" style="word-break: break-all;">{{scope.row.attachments}}</a>
</div>
</template>
</el-table-column>
<el-table-column prop="in_put_time" label="入仓时间" align="center" />
<el-table-column prop="purchasing_agent" label="采购人" align="center" />
<el-table-column prop="admin_user.username" label="创建人" align="center" />
<el-table-column prop="note" label="备注" align="center" />
<el-table-column prop="created_at" 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>
</el-card>
<el-dialog v-model="showDialog" width="900px" title="新增" @close="resetForm">
<el-form label-position="right" label-width="110px">
<el-form-item label="采购类型:">
<el-radio-group v-model="itemInfo.type">
<el-radio label="default">默认</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="供应商:">
<el-select v-model="itemInfo.supplier_id" placeholder="请选择" clearable filterable>
<el-option v-for="it in suppliersList" :key="it.id" :label="it.name" :value="it.id" />
</el-select>
</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.purchasing_agent" clearable></el-input>
</el-form-item>
<el-form-item label="入仓时间:">
<el-date-picker
v-model="itemInfo.in_put_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 v-model="itemInfo.batch_number" clearable></el-input>
</el-form-item>
<el-form-item label="采购单:">
<el-upload
ref="uploadRef"
action="/api/upload/img"
:headers="headers"
:on-remove="handleImgRemove"
:on-error="handleUploadError"
:on-preview="handlePreview"
:on-success="handleImgSuccess"
: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-item label="附件:">
<el-upload
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.note" type="textarea" :rows="4"></el-input>
</el-form-item>
</el-form>
<div v-for="(item, i) in skusList" :key="i" class="skuBox">
<div class="tit">采购商品{{ i + 1 }}</div>
<el-form label-width="110px" :inline="true">
<!-- <el-form-item label="所属商品:">
<el-select v-model="item.goods_id" placeholder="请选择" clearable filterable style="width: 220px;" @change="changeGoods(item)">
<el-option v-for="it in allGoodsList" :key="it.id" :label="it.title" :value="it.id" />
</el-select>
</el-form-item> -->
<el-form-item label="商品/规格:" style="width: 100%;">
<el-select v-model="item.sku_id" placeholder="请选择" clearable filterable style="width: 680px;">
<el-option v-for="it in guigeList" :key="it.id" :label="it.goods && it.goods.title + ' - ' + it.title" :value="it.id" />
</el-select>
</el-form-item>
<el-form-item label="采购数量:">
<el-input-number v-model="item.num" :min="0" style="width: 270px;" />
</el-form-item>
<el-form-item label="采购成本:">
<el-input placeholder="采购成本" v-model="item.cost" clearable style="width: 270px;"></el-input>
</el-form-item>
<el-form-item label="生产日期:">
<el-date-picker
v-model="item.production_date"
type="date"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
placeholder="选择日期"
style="width: 270px;"
clearable>
</el-date-picker>
</el-form-item>
<el-form-item label="出厂日期:">
<el-date-picker
v-model="item.factory_date"
type="date"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
placeholder="选择日期"
style="width: 270px;"
clearable>
</el-date-picker>
</el-form-item>
<el-form-item label="有效期类型:">
<el-radio-group v-model="item.validity_type" style="width: 270px;">
<el-radio label="day"></el-radio>
<el-radio label="month"></el-radio>
<el-radio label="year"></el-radio>
<el-radio label="none">长期</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="有效时间:">
<el-input-number v-model="item.validity" :min="0" style="width: 270px;" />
</el-form-item>
<el-form-item label="批次号:">
<el-input placeholder="批次号" v-model="item.batch_number" clearable style="width: 270px;"></el-input>
</el-form-item>
<el-form-item label=" ">
<el-button type="danger" @click="handleSkuDelete(i)" size="small"><el-icon><Delete /></el-icon>&nbsp;删除</el-button>
</el-form-item>
</el-form>
</div>
<el-form label-position="right" label-width="110px">
<el-form-item label="">
<el-button type="success" @click="toAddSku()">增加采购商品</el-button>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="showDialog = false">取消</el-button>
<el-button type="primary" @click="commitOpa()" :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({
goodsList: [],
page: 1,
pageSize: 10,
total: 0,
loading: false,
pickerTime: [],
showDialog: false,
opa_loading: false,
headers: {
Authorization: localStorage.getItem('token'),
'Shop-Id': localStorage.getItem('shopId') || ''
},
picVisible: false,
dialogImageUrl: '',
imgsList: [],
fileList: [],
Type: {
'default': '默认'
},
warehouseList: [],
suppliersList: [],
guigeList: [],
itemInfo: {},
skusList: [],
qaFileList: [],
allGoodsList: [],
})
function handleSearch() {
data.page = 1
fetchData()
}
const fetchData = () => {
data.loading = true
let params = {
page: data.page,
pageSize: data.pageSize,
service_id: data.service_id,
start_date: data.pickerTime ? data.pickerTime[0] : '',
end_date: data.pickerTime ? data.pickerTime[1] : ''
}
get(`/api/purchases`, 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.imgsList = []
data.qaFileList = []
data.skusList = []
data.itemInfo = {
type: 'default'
}
data.showDialog = true
}
function commitOpa() {
if(!data.skusList.length) {
ElMessage({ type: 'info', message: '请添加采购商品' })
return
}
data.opa_loading = true
let imgs = []
data.imgsList.forEach((it) => {
imgs.push(it.url)
})
let params = {
...data.itemInfo
}
params.goodsSkus = data.skusList
params.images = imgs
params.attachments = data.qaFileList.length ? data.qaFileList[0].url : ''
post(`/api/purchases`, 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)
})
}
function handleImgRemove(res, ress) {
data.replyImg = ress
}
function handleUploadError(err) {
if(JSON.parse(err.message) && JSON.parse(err.message).message) {
ElMessage({ type: 'error', message: JSON.parse(err.message).message })
}
}
function handlePreview(File) {
data.dialogImageUrl = File.url
data.picVisible = true
}
function handleImgSuccess(res) {
data.imgsList.push({url: res.data.link})
}
function handleFileSuccess(res, ress) {
2025-08-29 17:25:42 +08:00
if (res.code === 0) {
data.qaFileList = [{ name: ress.name, url: res.data.link }]
2025-06-14 10:30:10 +08:00
}
2025-08-29 17:25:42 +08:00
}
function handleFileRemove(res, ress) {
data.qaFileList = ress
}
2025-06-14 10:30:10 +08:00
2025-08-29 17:25:42 +08:00
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!')
2025-06-14 10:30:10 +08:00
return false
}
2025-08-29 17:25:42 +08:00
} else {
ElMessage.error('上传文件格式不正确')
return false
2025-06-14 10:30:10 +08:00
}
2025-08-29 17:25:42 +08:00
}
2025-06-14 10:30:10 +08:00
function handleSkuDelete(index) {
data.skusList.splice(index, 1)
}
const uploadRef = ref(null)
const resetForm = () => {
data.imgsList = []
nextTick(() => {
uploadRef.value.clearFiles()
})
}
function toAddSku() {
let sku = {
goods_id: '',
sku_id: '',
num: 1,
cost: '',
production_date: '',
factory_date: '',
validity_type: '',
validity: '',
batch_number: ''
}
data.skusList.push(sku)
}
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 getSkusList() {
get(`/api/all/goods-skus`).then((res) => {
data.guigeList = res.data
})
}
function getAllGoodsList() {
get(`/api/all/goods`).then((res) => {
data.allGoodsList = res.data
})
}
function changeGoods(row) {
row.sku_id = ''
get(`/api/all/goods-skus`, {goods_id: row.goods_id}).then((res) => {
data.guigeList = res.data
})
}
onMounted(() => {
fetchData()
getWarehouseList()
getSuppliersList()
getSkusList()
getAllGoodsList()
})
return {
uploadRef,
...toRefs(data),
handleSearch,
handleCurrentChange,
handleSizeChange,
fetchData,
handleAdd,
commitOpa,
handleImgRemove,
handleUploadError,
handlePreview,
handleImgSuccess,
handleSkuDelete,
resetForm,
toAddSku,
handleFileSuccess,
handleFileRemove,
previewFile,
handleBeforeUpload,
getWarehouseList,
getSuppliersList,
getSkusList,
getAllGoodsList,
changeGoods
}
}
}
</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: 80px;
font-size: 14px;
text-align: right;
box-sizing: border-box;
}
.right{
width: calc(100% - 100px);
}
.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>