factory_mp/pages/mpr/warehouse_entry_form.vue

284 lines
11 KiB
Vue

<!-- 入库单审批 -->
<template>
<view class="form-page">
<scroll-view scroll-y class="form-scroll">
<uni-forms v-model="form" label-width="200rpx" ref="customForm">
<!-- 审批状态卡片 -->
<view class="form-card" v-if="form.ticket_">
<ticketd :ticket_="form.ticket_"></ticketd>
</view>
<!-- 基本信息 -->
<view class="form-card">
<view class="form-card-title">入库信息</view>
<uni-forms-item label="编号" v-if="form.number">
<span>{{form.number}}</span>
</uni-forms-item>
<uni-forms-item label="所属部门">
<span>{{form.belong_dept_name || userDeptName}}</span>
</uni-forms-item>
<uni-forms-item label="操作人">
<span>{{form.create_by_name || userName}}</span>
</uni-forms-item>
<uni-forms-item label="仓库" required>
<uni-data-select
v-if="mode!='show'"
v-model="form.warehouse"
:localdata="warehouseOptions"
/>
<span v-else>{{form.warehouse_name}}</span>
</uni-forms-item>
<uni-forms-item label="入库日期" required>
<picker mode="date" :value="form.entry_date" @change="(e)=>{form.entry_date=e.detail.value}" v-if="mode!='show'">
<view class="picker-value">{{form.entry_date || '请选择日期'}}</view>
</picker>
<span v-else>{{form.entry_date}}</span>
</uni-forms-item>
<uni-forms-item label="入库类型" required>
<uni-data-select
v-if="mode!='show'"
v-model="form.entry_type"
:localdata="entryTypeList"
/>
<span v-else>{{form.entry_type_display || getLabel(entryTypeList, form.entry_type)}}</span>
</uni-forms-item>
<uni-forms-item label="入库方式" required>
<uni-data-select
v-if="mode!='show'"
v-model="form.entry_method"
:localdata="entryMethodList"
/>
<span v-else>{{form.entry_method_display || getLabel(entryMethodList, form.entry_method)}}</span>
</uni-forms-item>
<uni-forms-item label="合计金额">
<span style="font-weight:bold;color:#E37318;">¥ {{calcTotalAmount}}</span>
</uni-forms-item>
<uni-forms-item label="备注">
<textarea placeholder-style="color:#c0c4cc" v-model="form.note" placeholder="请输入备注" class="form-textarea" v-if="mode!='show'"/>
<span v-else>{{form.note}}</span>
</uni-forms-item>
</view>
<!-- 入库明细 -->
<view class="form-card">
<view class="form-card-title">入库明细</view>
<view v-if="mode!='show'" class="item-add-row">
<button class="item-add-btn" @click="addItem" size="mini">+ 添加物品</button>
</view>
<view v-for="(item, idx) in items" :key="idx" class="item-card">
<view class="item-card-header">
<text class="item-card-index">第{{idx+1}}项</text>
<text v-if="mode!='show'" class="item-card-del" @click="delItem(idx)">删除</text>
</view>
<uni-forms-item label="名称" required>
<uni-easyinput v-model="item.name" placeholder="名称" v-if="mode!='show'"/>
<span v-else>{{item.name}}</span>
</uni-forms-item>
<uni-forms-item label="规格">
<uni-easyinput v-model="item.spec" placeholder="规格" v-if="mode!='show'"/>
<span v-else>{{item.spec}}</span>
</uni-forms-item>
<uni-forms-item label="单位">
<uni-easyinput v-model="item.unit" placeholder="单位" v-if="mode!='show'"/>
<span v-else>{{item.unit}}</span>
</uni-forms-item>
<uni-forms-item label="数量" required>
<uni-number-box v-model="item.quantity" :min="0" :step="1" v-if="mode!='show'"/>
<span v-else>{{item.quantity}}</span>
</uni-forms-item>
<uni-forms-item label="单价">
<uni-number-box v-model="item.unit_price" :min="0" :step="0.01" v-if="mode!='show'"/>
<span v-else>{{item.unit_price}}</span>
</uni-forms-item>
<uni-forms-item label="金额">
<span style="font-weight:bold;">¥ {{calcRowAmount(item)}}</span>
</uni-forms-item>
<uni-forms-item label="供应商名称">
<uni-easyinput v-model="item.supplier_name" placeholder="供应商名称" v-if="mode!='show'"/>
<span v-else>{{item.supplier_name}}</span>
</uni-forms-item>
<uni-forms-item label="账单是否收到">
<switch :checked="item.invoice_received" @change="(e)=>{item.invoice_received=e.detail.value}" v-if="mode!='show'" color="#2BA471"/>
<span v-else>{{item.invoice_received ? '已收到' : '未收到'}}</span>
</uni-forms-item>
<uni-forms-item label="备注">
<uni-easyinput v-model="item.note" placeholder="备注" v-if="mode!='show'"/>
<span v-else>{{item.note}}</span>
</uni-forms-item>
</view>
<view v-if="items.length === 0" class="empty-hint">暂无入库物品</view>
</view>
</uni-forms>
</scroll-view>
<view class="footer_fixed">
<button v-if="mode=='edit'" class="form-btn form-btn-danger" @click="handleDel" :loading="saveLoading" :disabled="saveLoading">
删除
</button>
<button v-if="mode!='show'" class="form-btn form-btn-primary" @click="handleSave" :loading="saveLoading" :disabled="saveLoading">
提交审批
</button>
<ticketd_b :workflow_key="'wf_warehouse_entry'" v-if="form.ticket_ && mode == 'show'" :t_id="form.id" :ticket_="form.ticket_"
:ticket_data="ticket_data" @success="()=>{uni.navigateBack()}" ref="ticketd_b"></ticketd_b>
</view>
</view>
</template>
<script>
import ticketd_b from "../wf/ticketd_b.vue"
import ticketd from "../wf/ticketd.vue"
export default {
components: { ticketd_b, ticketd },
data(){
return{
saveLoading: false,
mode:"add",
t_id: null,
form:{
entry_type: 'raw_normal',
entry_method: 'purchase',
},
items:[],
ticket_data:{},
userName:'',
userDeptName:'',
warehouseOptions:[],
entryTypeList: [
{ value: 'raw_normal', text: '原材料正常入库' },
{ value: 'raw_estimated', text: '原材料暂估入库' },
{ value: 'product', text: '产品入库' },
{ value: 'other', text: '其他' },
],
entryMethodList: [
{ value: 'purchase', text: '采购' },
{ value: 'self_made', text: '自制' },
{ value: 'other', text: '其他' },
],
}
},
computed: {
isEditable() {
return this.mode === 'add' || this.mode === 'edit'
},
calcTotalAmount() {
let total = 0
this.items.forEach(row => {
total += Number(this.calcRowAmount(row))
})
return total.toFixed(2)
}
},
async onLoad(options) {
let userInfo = uni.getStorageSync("userInfo")
this.userName = userInfo.name
this.userDeptName = userInfo.belong_dept_name || ''
this.mode = options.mode || 'add'
this.t_id = options.t_id || null
// 加载仓库列表
try {
const res = await this.$api.warehouseList({ page: 0 })
const list = Array.isArray(res) ? res : (res.results || [])
this.warehouseOptions = list.map(w => ({ value: w.id, text: w.name }))
} catch(e) {}
if(this.t_id) {
const res = await this.$api.warehouseEntryItemDetail(this.t_id)
this.form = res
this.items = res.items_ || []
if(res.ticket_ && res.ticket_.state_.type == 1 && res.create_by == userInfo.id) {
this.mode = "edit"
} else {
this.mode = "show"
}
}
},
methods:{
calcRowAmount(row) {
return (Number(row.quantity || 0) * Number(row.unit_price || 0)).toFixed(2)
},
getLabel(list, value) {
if (!list || !value) return ''
const item = list.find(i => String(i.value) === String(value))
return item ? item.text : ''
},
addItem() {
this.items.push({
name: '', spec: '', unit: '',
quantity: 0, unit_price: 0,
supplier_name: '', invoice_received: false, note: ''
})
},
delItem(idx) {
this.items.splice(idx, 1)
},
async handleDel(){
await this.$api.warehouseEntryDelete(this.form.id)
uni.navigateBack()
},
async handleSave(){
if(!this.form.warehouse) {
uni.showToast({ title: '请选择仓库', icon: 'none' }); return
}
if(!this.form.entry_date) {
uni.showToast({ title: '请选择入库日期', icon: 'none' }); return
}
if(this.items.length === 0) {
uni.showToast({ title: '请至少添加一项入库物品', icon: 'none' }); return
}
for(let i = 0; i < this.items.length; i++) {
if(!this.items[i].name) {
uni.showToast({ title: `${i+1}项:请填写名称`, icon: 'none' }); return
}
}
this.saveLoading = true
try {
const payload = {
warehouse: this.form.warehouse,
entry_date: this.form.entry_date,
entry_type: this.form.entry_type,
entry_method: this.form.entry_method,
note: this.form.note,
items: this.items.map(row => ({
name: row.name,
spec: row.spec,
unit: row.unit,
quantity: row.quantity,
unit_price: row.unit_price,
supplier_name: row.supplier_name,
invoice_received: row.invoice_received,
note: row.note
}))
}
if(this.mode === 'edit') {
await this.$api.warehouseEntryUpdate(this.form.id, payload)
} else {
await this.$api.warehouseEntryCreate(payload)
}
uni.navigateBack()
} catch(e) {
uni.showToast({ title: '提交失败', icon: 'none' })
} finally {
this.saveLoading = false
}
},
}
}
</script>
<style lang="scss" scoped>
.form-page { min-height: 100vh; background: #F0F2F5; }
.form-scroll { padding: 0; padding-bottom: 180rpx; }
.form-card { background: #fff; border-radius: 0; padding: 24rpx; margin-bottom: 0; box-shadow: none; }
.form-card-title { font-size: 30rpx; font-weight: 600; color: #1F2937; margin-bottom: 16rpx; padding-left: 16rpx; border-left: 6rpx solid #2BA471; }
.form-textarea { width: 100%; min-height: 120rpx; border: 2rpx solid #E5E7EB; border-radius: 12rpx; padding: 16rpx; font-size: 28rpx; color: #374151; box-sizing: border-box; background: #F9FAFB; }
.form-btn { flex: 1; height: 80rpx; line-height: 80rpx; border-radius: 14rpx !important; font-size: 28rpx; font-weight: 500; border: none !important; }
.form-btn-primary { background: linear-gradient(135deg, #2BA471, #1F8C5E) !important; color: #fff !important; box-shadow: 0 4rpx 12rpx rgba(43,164,113,0.2); }
.form-btn-danger { background: linear-gradient(135deg, #EF4444, #DC2626) !important; color: #fff !important; box-shadow: 0 4rpx 12rpx rgba(239,68,68,0.3); }
.picker-value { padding: 12rpx 16rpx; background: #F9FAFB; border: 2rpx solid #E5E7EB; border-radius: 8rpx; font-size: 28rpx; color: #374151; }
.item-add-row { display: flex; justify-content: flex-end; margin-bottom: 16rpx; }
.item-add-btn { background: #2BA471 !important; color: #fff !important; font-size: 24rpx; border: none !important; border-radius: 8rpx !important; padding: 0 24rpx !important; height: 56rpx; line-height: 56rpx; }
.item-card { background: #F9FAFB; border-radius: 12rpx; padding: 20rpx; margin-bottom: 16rpx; border: 1rpx solid #E5E7EB; }
.item-card-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12rpx; }
.item-card-index { font-size: 26rpx; font-weight: 600; color: #2BA471; }
.item-card-del { font-size: 24rpx; color: #EF4444; }
.empty-hint { text-align: center; padding: 40rpx 0; color: #9CA3AF; font-size: 26rpx; }
</style>