Jelajahi Sumber

feat: 销售报价单审批

liujt 2 bulan lalu
induk
melakukan
c79a6392b1

+ 114 - 0
api/saleManage/quotation.js

@@ -0,0 +1,114 @@
+import { post, get, postJ } from '@/utils/request'
+import Vue from 'vue'
+
+const baseUrl = Vue.prototype.apiUrl
+
+/**
+ * 获取商机列表
+ */
+export async function getTableList(params) {
+  const res = await get(baseUrl + `/eom/businessopportunity/page`, params)
+  if (res.code == 0) {
+    return res.data
+  }
+  return Promise.reject(new Error(res.message))
+}
+
+/**
+ * 查询客户联系人列表
+ */
+export async function getcontactlink(params) {
+  const res = await get(baseUrl + `/eom/contactlink/list/`, params)
+  if (res.code == 0) {
+    return res.data
+  }
+  return Promise.reject(new Error(res.message))
+}
+
+/**
+ * 获取信息详情
+ */
+export async function getQuotationDetailAPI(id) {
+  const res = await get(baseUrl + `/eom/quote/getById/${id}`)
+  if (res.code == 0) {
+    return res.data
+  }
+  return Promise.reject(new Error(res.message))
+}
+
+/**
+ * 更新信息
+ */
+export async function UpdateInformation(data) {
+  const res = await post(baseUrl + `/eom/quote/update`, data)
+  if (res.code == 0) {
+    return res.data
+  }
+  return Promise.reject(new Error(res.message))
+}
+
+/**
+ * 生产主管指派技术员
+ */
+export async function assignTechnician(data) {
+  const res = await post(baseUrl + `/bpm/quoteApprove/assignTechnician`, data)
+  if (res.code == 0) {
+    return res.data
+  }
+  return Promise.reject(new Error(res.message))
+}
+
+/**
+ * 更新技术员
+ */
+export async function updateTech(data) {
+  const res = await post(baseUrl + `/eom/quote/updateTech`, data)
+  if (res.code == 0) {
+    return res.data
+  }
+  return Promise.reject(new Error(res.message))
+}
+
+/**
+ * 生产主管复核
+ */
+export async function productionSupervisorReApprove(data) {
+  const res = await post(baseUrl + `/bpm/quoteApprove/productionSupervisorReApprove`, data)
+  if (res.code == 0) {
+    return res.data
+  }
+  return Promise.reject(new Error(res.message))
+}
+
+/**
+ * 销售主管审批
+ */
+export async function salesManagerApprove(data) {
+  const res = await post(baseUrl + `/bpm/quoteApprove/salesManagerApprove`, data)
+  if (res.code == 0) {
+    return res.data
+  }
+  return Promise.reject(new Error(res.message))
+}
+
+/**
+ * 销售员补充
+ */
+export async function salesmanApprove(data) {
+  const res = await post(baseUrl + `/bpm/quoteApprove/salesmanApprove`, data)
+  if (res.code == 0) {
+    return res.data
+  }
+  return Promise.reject(new Error(res.message))
+}
+
+/**
+ * 流程作废
+ */
+export async function cancel(data) {
+  const res = await post(baseUrl + `/bpm/quoteApprove/notPass`, data)
+  if (res.code == 0) {
+    return res
+  }
+  return Promise.reject(new Error(res.message))
+}

+ 8 - 0
pages.json

@@ -110,6 +110,14 @@
 				"navigationBarTextStyle": "white"
 			}
 		},
+		{ // 报价单审批
+			"path": "pages/home/wt/components/quotation/processTask",
+			"style": {
+				"navigationBarTitleText": "",
+				"navigationStyle": "custom",
+				"navigationBarTextStyle": "white"
+			}
+		},
 		{
 			"path": "pages/home/wt/components/businessOpportunity/processTask",
 			"style": {

+ 163 - 0
pages/home/wt/components/common/commonProductList.vue

@@ -0,0 +1,163 @@
+<template>
+	<view>
+		<view v-for="(item, index) in list" :key="index">
+			<view class="product-card">
+				<view class="card-header">
+					<text class="product-name">{{ item.productName || '物品' + (index + 1) }}</text>
+					<text class="product-price">{{ item.productCode || '-' }}</text>
+				</view>
+				<view class="card-body">
+					<view class="info-row" v-for="(field, idx) in tableField" :key="idx">
+						<text class="info-label">{{ field.label }}:</text>
+						<text class="info-value">{{ formatValue(item, field) }} {{ field.unit || '' }}</text>
+					</view>
+				</view>
+			</view>
+		</view>
+		<u-empty v-if="!list || list.length === 0" text="暂无物品清单" marginTop="100"></u-empty>
+	</view>
+</template>
+
+<script>
+import {transactionMethodsOp,shippingModeOp,shippingModePurchaseOp, pricingWayList, levelList, quoteTypeOp} from '@/enum/dict.js'
+import { mapGetters } from 'vuex'
+export default {
+	name: 'common-product-list',
+	computed: {
+		...mapGetters(['getDictValue'])
+	},
+	props: {
+		list: {
+			type: Array,
+			default: () => []
+		},
+		tableField: {
+			type: Array,
+			default: () => [
+				{ label: '类型', field: 'productCategoryName' },
+				// { label: '名称', field: 'productName' },
+				{ label: '计价方式', field: 'pricingWay', type: 'pricingWay' },
+				// { label: '编码', field: 'productCode' },
+				{ label: '规格', field: 'specification' },
+				{ label: '牌号', field: 'brandNo' },
+				{ label: '客户代号', field: 'customerMark' },
+				{ label: '包装规格', field: 'packingSpecification' },
+				{ label: '价格类型', field: 'goodsPriceType', type: 'dict', dictName: '商品价格类型' },
+				{ label: '单价', field: 'singlePrice' },
+				{ label: '折让单价', field: 'discountSinglePrice' },
+				{ label: '单重', field: 'singleWeight' },
+				{ label: '总重', field: 'totalWeight' },
+				{ label: '增重重量', field: 'increaseTotalWeight' },
+				{ label: '数量', field: 'saleCount' },
+				{ label: '计量数量', field: 'totalCount' },
+				{ label: '税率', field: 'taxRate', unit: '%'},
+				{ label: '合计', field: 'totalPrice' },
+				{ label: '折让合计金额', field: 'discountTotalPrice' },
+			]
+		}
+	},
+	data() {
+		return {
+			pricingWayList
+		}
+	},
+	methods: {
+		// 格式化字段值
+		formatValue(item, field) {
+			let value = item[field.field]
+			// 数量字段显示单位
+			if (field.field === 'saleCount') {
+				const unit = item.saleUnit || ''
+				return value ? value + (unit ? ' ' + unit : '') : '-'
+			}
+			// 计量数量字段显示单位
+			if (field.field === 'totalCount') {
+				const unit = item.measuringUnit || ''
+				return value ? value + (unit ? ' ' + unit : '') : '-'
+			}
+			// 单重字段显示单位
+			if (field.field === 'singleWeight') {
+				const unit = item.weightUnit || ''
+				return value ? value + (unit ? ' ' + unit : '') : '-'
+			}
+			// 总重字段显示单位
+			if (field.field === 'totalWeight') {
+				const unit = item.weightUnit || ''
+				return value ? value + (unit ? ' ' + unit : '') : '-'
+			}
+			// 增重重量字段显示单位
+			if (field.field === 'increaseTotalWeight') {
+				const unit = item.weightUnit || ''
+				return value ? value + (unit ? ' ' + unit : '') : '-'
+			}
+			// 计价方式特殊处理
+			if (field.type === 'pricingWay') {
+				const found = this.pricingWayList.find(p => p.id === value)
+				return found ? found.name : '-'
+			}
+			// 字典类型处理
+			if (field.type === 'dict') {
+				return this.getDictValue(field.dictName, value) || '-'
+			}
+			return value || '-'
+		}
+	}
+}
+</script>
+
+<style scoped>
+.product-card {
+	margin: 20rpx;
+	padding: 20rpx;
+	background: #fff;
+	border-radius: 12rpx;
+	box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
+}
+
+.card-header {
+	display: flex;
+	justify-content: space-between;
+	align-items: center;
+	padding-bottom: 16rpx;
+	border-bottom: 1rpx solid #eee;
+	margin-bottom: 16rpx;
+}
+
+.product-name {
+	font-size: 28rpx;
+	font-weight: bold;
+	color: #333;
+}
+
+.product-price {
+	font-size: 26rpx;
+	/* color: #157a2c; */
+	/* font-weight: bold; */
+}
+
+.card-body {
+	display: flex;
+	flex-wrap: wrap;
+}
+
+.info-row {
+	width: 50%;
+	display: flex;
+	padding: 8rpx 0;
+	box-sizing: border-box;
+}
+
+.info-label {
+	color: #666;
+	font-size: 26rpx;
+	flex-shrink: 0;
+}
+
+.info-value {
+	color: #333;
+	font-size: 26rpx;
+	overflow: hidden;
+	text-overflow: ellipsis;
+	white-space: nowrap;
+}
+</style>

+ 0 - 0
pages/home/wt/components/salesOrderInvoice/processTask.vue → pages/home/wt/components/quotation/processTask.vue


+ 119 - 0
pages/home/wt/components/quotation/taskForm.vue

@@ -0,0 +1,119 @@
+<template>
+	<view class="">
+		<u-sticky offset-top="50">
+			<u-subsection fontSize='25' mode='subsection' :list="list" :current="curNow" @change="sectionChange"
+				activeColor='#157A2C'></u-subsection>
+		</u-sticky>
+		<view v-show='curNow===0'>
+			<u--form style="margin: 0 20px;" labelPosition="left" :model="form" ref="uForm" labelWidth='200rpx'>
+				<u-form-item label="关联商机名称" prop="opportunityName" borderBottom>
+					{{ form.opportunityName || '-' }}
+				</u-form-item>
+				<u-form-item label="报价方名称" prop="quoteName" borderBottom>
+					{{ form.quoteName || '-' }}
+				</u-form-item>
+				<u-form-item label="询价方名称" prop="contactName" borderBottom>
+					{{ form.contactName || '-' }}
+				</u-form-item>
+				<u-form-item label="报价方联系人" prop="quoteLinkName" borderBottom>
+					{{ form.quoteLinkName || '-' }}
+				</u-form-item>
+				<u-form-item label="询价方联系人" prop="contactLinkName" borderBottom>
+					{{ form.contactLinkName || '-' }}
+				</u-form-item>
+				<u-form-item label="报价方联系电话" prop="quoteTel" borderBottom>
+					{{ form.quoteTel || '-' }}
+				</u-form-item>
+				<u-form-item label="询价方电话" prop="contactTel" borderBottom>
+					{{ form.contactTel || '-' }}
+				</u-form-item>
+				<u-form-item label="报价方传真" prop="quoteFax" borderBottom>
+					{{ form.quoteFax || '-' }}
+				</u-form-item>
+				<u-form-item label="询价方传真" prop="contactFax" borderBottom>
+					{{ form.contactFax || '-' }}
+				</u-form-item>
+				<u-form-item label="报价方Email" prop="quoteEmail" borderBottom>
+					{{ form.quoteEmail || '-' }}
+				</u-form-item>
+				<u-form-item label="询价方Email" prop="contactEmail" borderBottom>
+					{{ form.contactEmail || '-' }}
+				</u-form-item>
+				<u-form-item label="报价方地址" prop="quoteAddress" borderBottom>
+					{{ form.quoteAddress || '-' }}
+				</u-form-item>
+				<u-form-item label="询价方地址" prop="contactAddress" borderBottom>
+					{{ form.contactAddress || '-' }}
+				</u-form-item>
+				<u-form-item label="是否接受拆单" prop="acceptUnpack" borderBottom>
+					{{ form.acceptUnpack == 1 ? '接受' : '不接受' }}
+				</u-form-item>
+				<u-form-item label="附件" prop="askFile" borderBottom>
+					<fileMain v-model="form.askFile" type="view"></fileMain>
+				</u-form-item>
+				<u-form-item label="结算方式" prop="settlementModeName" borderBottom>
+					{{ form.settlementModeName || '-' }}
+				</u-form-item>
+			</u--form>
+		</view>
+		<view v-show='curNow===1'>
+			<u-sticky offset-top="100">
+				<u-tag
+					:text="`总计: ${form.totalPrice || 0}`"
+					size="large" type="success"></u-tag>
+			</u-sticky>
+			<quote-product-list :list="form.quoteProductList"></quote-product-list>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		getQuotationDetailAPI
+	} from '@/api/saleManage/quotation.js'
+	import fileMain from "@/pages/doc/index.vue"
+	import quoteProductList from "../common/commonProductList.vue"
+	import {transactionMethodsOp,shippingModeOp,shippingModePurchaseOp, pricingWayList, levelList, quoteTypeOp} from '@/enum/dict.js'
+	export default {
+		components: {
+			fileMain,
+			quoteProductList
+		},
+		props: {
+			businessId: {
+				default: ''
+			},
+			taskDefinitionKey: {
+				default: ''
+			},
+		},
+		computed: {
+	
+		},
+		data() {
+			return {
+				form: {},
+				list: ['基本信息', '物品清单'],
+				curNow: 0
+			}
+		},
+		async mounted() {
+			await this.getDetailData(this.businessId);
+		},
+		methods: {
+			sectionChange(index) {
+				this.curNow = index;
+			},
+			async getDetailData(id) {
+				const data = await getQuotationDetailAPI(id);
+				this.form = data;
+			}
+		}
+	}
+</script>
+
+<style scoped>
+.btnConcel {
+		margin-top: 20rpx;
+	}
+</style>

+ 0 - 0
pages/home/wt/components/salesOrderInvoice/taskSubmit.vue → pages/home/wt/components/quotation/taskSubmit.vue


+ 0 - 250
pages/home/wt/components/salesOrderInvoice/taskForm.vue

@@ -1,250 +0,0 @@
-<template>
-	<view class="">
-		<u-sticky offset-top="50">
-			<u-subsection fontSize='25' mode='subsection' :list="list" :current="curNow" @change="sectionChange"
-				activeColor='#157A2C'></u-subsection>
-		</u-sticky>
-
-		<view v-show='curNow===0'>
-			<u--form style="margin: 0 20px;" labelPosition="left" :model="form" ref="uForm" labelWidth='140rpx'>
-				<u-form-item label="订单编号" prop="orderNo" borderBottom>
-					<u--input style="width: 100%;" disabled v-model="form.orderNo"></u--input>
-				</u-form-item>
-				<u-form-item label="合同名称" prop="contractName" borderBottom>
-					<u--input style="width: 100%;" disabled v-model="form.contractName"></u--input>
-				</u-form-item>
-				<u-form-item label="合同编号" prop="contractNumber" borderBottom>
-					<u--input style="width: 100%;" disabled v-model="form.contractNumber"></u--input>
-				</u-form-item>
-				<u-form-item label="项目名称" prop="projectName" borderBottom>
-					<u--input style="width: 100%;" disabled v-model="form.projectName"></u--input>
-				</u-form-item>
-				<u-form-item label="优惠总金额" prop="payAmount" borderBottom>
-					<u--input style="width: 100%;" disabled v-model="form.payAmount"></u--input>
-				</u-form-item>
-
-				<u-form-item label="订单总金额" prop="totalAmount" borderBottom>
-					<u--input style="width: 100%;" disabled v-model="form.totalAmount"></u--input>
-				</u-form-item>
-				<u-form-item label="附件" prop="orderFiles" borderBottom>
-					<fileMain v-model="form.orderFiles" type="view"></fileMain>
-				</u-form-item>
-			</u--form>
-
-		</view>
-		<view v-show='curNow===1'>
-			<u--form style="margin: 0 20px;" labelPosition="left" :model="form" ref="uForm" labelWidth='140rpx'>
-				<u-form-item label="客户名称" prop="partaName" borderBottom>
-					<u--input style="width: 100%;" disabled v-model="form.partaName"></u--input>
-				</u-form-item>
-				<u-form-item label="客户信用代码" prop="partaUnifiedSocialCreditCode" borderBottom>
-					<u--input style="width: 100%;" disabled v-model="form.partaUnifiedSocialCreditCode"></u--input>
-				</u-form-item>
-				<u-form-item label="客户联系人" prop="partaLinkName" borderBottom>
-					<u--input style="width: 100%;" disabled v-model="form.partaLinkName"></u--input>
-				</u-form-item>
-				<u-form-item label="客户电话" prop="partaTel" borderBottom>
-					<u--input style="width: 100%;" disabled v-model="form.partaTel"></u--input>
-				</u-form-item>
-				<u-form-item label="客户传真" prop="partaFax" borderBottom>
-					<u--input style="width: 100%;" disabled v-model="form.partaFax"></u--input>
-				</u-form-item>
-				<u-form-item label="客户Email" prop="partaEmail" borderBottom>
-					<u--input style="width: 100%;" disabled v-model="form.partaEmail"></u--input>
-				</u-form-item>
-				<u-form-item label="客户地址" prop="partaAddress" borderBottom>
-					<u--input style="width: 100%;" disabled v-model="form.partaAddress"></u--input>
-				</u-form-item>
-
-
-				<u-form-item label="售出方名称" prop="partbName" borderBottom>
-					<u--input style="width: 100%;" disabled :value='`${form.partbName}`'></u--input>
-				</u-form-item>
-				<u-form-item label="售出方信用代码" prop="partbUnifiedSocialCreditCode" borderBottom>
-					<u--input style="width: 100%;" disabled v-model="form.partbUnifiedSocialCreditCode"></u--input>
-				</u-form-item>
-				<u-form-item label="售出方联系人" prop="partbLinkName" borderBottom>
-					<u--input style="width: 100%;" disabled v-model="form.partbLinkName"></u--input>
-				</u-form-item>
-				<u-form-item label="售出方电话" prop="partbTel" borderBottom>
-					<u--input style="width: 100%;" disabled v-model="form.partbTel"></u--input>
-				</u-form-item>
-				<u-form-item label="售出方传真" prop="partbFax" borderBottom>
-					<u--input style="width: 100%;" disabled v-model="form.partbFax"></u--input>
-				</u-form-item>
-				<u-form-item label="售出方Email" prop="partbEmail" borderBottom>
-					<u--input style="width: 100%;" disabled v-model="form.partbEmail"></u--input>
-				</u-form-item>
-				<u-form-item label="售出方地址" prop="partbAddress" borderBottom>
-					<u--input style="width: 100%;" disabled v-model="form.partbAddress"></u--input>
-				</u-form-item>
-			</u--form>
-		</view>
-		<view v-show='curNow===2'>
-			<u-sticky offset-top="100">
-				<u-tag
-					:text="`总计: ${form.totalAmount&&form.totalAmount} 优惠总金额: ${form.payAmount&&form.payAmount}`"
-					size="large" type="success"></u-tag>
-			</u-sticky>
-			<view v-for="(item,index) in form['productList']" :key="index">
-				<u--form style="margin: 0 20px;" labelPosition="left" :model="form" ref="uForm" labelWidth='140rpx'>
-					<u-row v-for="(key,index1) in tableField" :key="index1">
-						<u-col :span="12">
-							<u-form-item :label="key.label" prop="categoryName" borderBottom>
-								<u--input style="width: 100%;" :title='item[key.field]' disabled
-									v-model="item[key.field]"></u--input>
-							</u-form-item>
-						</u-col>
-
-					</u-row>
-				</u--form>
-				<u-gap height="40" bgColor="#f0f0f0"></u-gap>
-			</view>
-
-		</view>
-		<view v-show='curNow===3'>
-			<view v-for="(item,index) in form['receiptPaymentList']" :key="index">
-				<u--form style="margin: 0 20px;" labelPosition="left" :model="form" ref="uForm" labelWidth='140rpx'>
-					<u-row v-for="(key,index1) in feeTableField" :key="index1">
-						<u-col :span="12">
-							<u-form-item :label="key.label" prop="categoryName" borderBottom>
-								<u--input style="width: 100%;" :title='item[key.field]' disabled
-									v-model="item[key.field]"></u--input>
-							</u-form-item>
-						</u-col>
-
-					</u-row>
-				</u--form>
-				<u-gap height="40" bgColor="#f0f0f0"></u-gap>
-			</view>
-		</view>
-	</view>
-</template>
-
-<script>
-	import {
-		getSaleOrderDetailAPI
-	} from '@/api/wt/index.js'
-	import fileMain from "@/pages/doc/index.vue"
-	import {transactionMethodsOp,shippingModeOp,shippingModePurchaseOp, pricingWayList, levelList, quoteTypeOp} from '@/enum/dict.js'
-	export default {
-		components: {
-			fileMain
-		},
-		props: {
-			businessId: {
-				default: ''
-			},
-			taskDefinitionKey: {
-				default: ''
-			},
-		},
-		computed: {
-			shippingModeOptions() {
-				return this.form.type == 2 ? shippingModePurchaseOp : shippingModeOp;
-			},
-			feeTableField() {
-				return [{
-						label: '期数',
-						field: 'issueNumber',
-					}, 
-					{
-						label: '款项类型',
-						field: 'typeName',
-					},
-					{
-						label: '款项名称',
-						field: 'moneyName',
-					},
-					{
-						label: '比例(%)',
-						field: 'ratio',
-					},
-					{
-						label: this.form.type == 2 ? '计划付款金额(元)' : '计划收款金额(元)',
-						field: 'price',
-					},
-					{
-						label: this.form.type == 2 ? '计划付款日期' : '计划收款日期',
-						field: 'deadLine',
-					},
-					{
-						label: '说明',
-						field: 'remark',
-					}
-				]
-			},
-		},
-		data() {
-			return {
-				form: {},
-				tableField: [{
-						label: '类型',
-						field: 'productCategoryName',
-					}, {
-						label: '名称',
-						field: 'productName',
-					},
-					{
-						label: '编码',
-						field: 'productCode',
-					},
-					{
-						field: 'specification',
-						label: '规格',
-
-					},
-					{
-						field: 'brandNo',
-						label: '牌号',
-
-					},
-					{
-						label: '客户代号',
-						field: 'customerMark',
-					},
-					{
-						label: '单价',
-						field: 'singlePrice',
-					},
-					{
-						label: '折让单价',
-						field: 'discountSinglePrice',
-					},
-					{
-						label: '数量',
-						field: 'totalCount',
-					},
-					{
-						label: '合计',
-						field: 'totalPrice',
-					},
-					{
-						label: '折让合计金额',
-						field: 'discountTotalPrice',
-					},
-				],
-				list: ['订单信息', '基本信息', '产品清单', '收款计划'],
-				curNow: 0
-			}
-		},
-		async mounted() {
-			await this.getDetailData(this.businessId);
-		},
-		methods: {
-			sectionChange(index) {
-				this.curNow = index;
-			},
-			async getDetailData(id) {
-				const data = await getSaleOrderDetailAPI(id);
-				this.form = data;
-			}
-		}
-	}
-</script>
-
-<style scoped>
-.btnConcel {
-		margin-top: 20rpx;
-	}
-</style>