pengyh пре 1 година
родитељ
комит
1ee84d4f5d

+ 64 - 0
src/api/activityOrder.js

@@ -0,0 +1,64 @@
+import request, { postBlob, getBlob, handleImport } from '@/utils/request'
+
+// 获取列表
+export function listPageV2(data) {
+  return request({
+    url: `/promotion/activity/list?moduleId=${data.moduleId}`,
+    method: 'post',
+    data
+  })
+}
+
+//导出
+export function pageExport(data, name) {
+  return postBlob({
+    url: '/promotion/activity/export',
+    data,
+    name
+  })
+}
+
+// 新增
+export function add(data) {
+  return request({
+    url: `/promotion/activity/add`,
+    method: 'post',
+    data
+  })
+}
+
+// 详情
+export function getDetail(params) {
+  return request({
+    url: `/promotion/activity/detail`,
+    method: 'post',
+    params
+  })
+}
+
+// 跟进
+export function follow(data) {
+  return request({
+    url: `/promotion/activity/batch/follow`,
+    method: 'post',
+    data
+  })
+}
+
+// 获取活动
+export function getActiveList(data) {
+  return request({
+    url: `/promotion/questionnaire/list`,
+    method: 'post',
+    data
+  })
+}
+
+//获取活动详情
+export function getActiveDetail(params) {
+  return request({
+    url: `/promotion/questionnaire/detail`,
+    method: 'post',
+    params
+  })
+}

+ 449 - 0
src/views/mallManagement/activityOrder/detail.vue

@@ -0,0 +1,449 @@
+<template>
+	<div class="s-page">
+		<el-page-header @back="goBack" :content="title"></el-page-header>
+		<el-divider></el-divider>
+		<el-card class="box-card">
+			<div slot="header" class="clearfix">
+				<span>基本信息</span>
+			</div>
+			<div class="mymain-container">
+				<el-form ref="formData" :rules="rules" :model="formData" label-width="110px" size="small" label-position="left">
+					<el-row :gutter="20" justify="start">
+						<el-col :span="6">
+							<el-form-item label="所属商户" :required="true" >
+								<el-input type="text" :value="companyName" disabled></el-input>
+							</el-form-item>
+						</el-col>
+						<el-col :span="6" style="height: 51px;">
+							<el-form-item label="活动名称" prop="promotionActivityId">
+								<el-select v-model="formData.active" :disabled="formType!=0" value-key="id" @change="(e)=>{
+									formData.promotionActivityId = e.id
+									formData.activeDate = [e.startTime,e.endTime]
+									this.getActiveDetail(e.id)
+								}" placeholder="请选择" style="width: 100%;">
+								    <el-option
+								      v-for="item in activeList"
+								      :key="item.id"
+								      :label="item.name"
+								      :value="item">
+								    </el-option>
+								  </el-select>
+							</el-form-item>
+						</el-col>
+						<el-col :span="12" style="margin-bottom: 1px;">
+							<el-form-item label="活动时间" prop="" class="is-required">
+								<el-date-picker
+								      v-model="formData.activeDate"
+									  disabled
+								      type="daterange"
+								      range-separator="至"
+								      start-placeholder="开始日期"
+								      end-placeholder="结束日期">
+								</el-date-picker>
+							</el-form-item>
+						</el-col>
+						<el-col :span="6">
+							<el-form-item label="客户名称" prop="userName">
+								<el-input type="text" :disabled="formType!=0" v-model="formData.userName" placeholder="请输入"></el-input>
+							</el-form-item>
+						</el-col>
+						<el-col :span="6">
+							<el-form-item label="联系人" prop="linkName">
+								<el-input type="text" :disabled="formType!=0" v-model="formData.linkName" placeholder="请输入"></el-input>
+							</el-form-item>
+						</el-col>
+						<el-col :span="6">
+							<el-form-item label="客户电话" prop="userMobile">
+								<el-input type="number" :disabled="formType!=0" v-model="formData.userMobile" placeholder="请输入"></el-input>
+							</el-form-item>
+						</el-col>
+						<el-col :span="6">
+							<el-form-item label="客户电话2" prop="userMobile2">
+								<el-input type="text" :disabled="formType!=0" v-model="formData.userMobile2" placeholder="请输入电话 (固话加区号)"></el-input>
+							</el-form-item>
+						</el-col>
+						<el-col :span="24">
+							<el-form-item label="客户地址" prop="userAddress">
+								<el-input type="text" v-model="formData.userAddress" :disabled="formType!=0" placeholder="详细地址"></el-input>
+							</el-form-item>
+						</el-col>
+						<template v-if="formType!=0">
+							<el-col :span="6">
+								<el-form-item label="提交人" prop="createBy">
+									<el-input type="text" v-model="formData.createBy" :disabled="true" placeholder="提交人"></el-input>
+								</el-form-item>
+							</el-col>
+							<el-col :span="6">
+								<el-form-item label="提交时间" prop="createTime">
+									<el-input type="text" v-model="formData.createTime" :disabled="true" placeholder="提交时间"></el-input>
+								</el-form-item>
+							</el-col>
+						</template>
+						
+					</el-row>
+				</el-form>
+			</div>
+		</el-card>
+		<el-card class="box-card">
+			<div slot="header" class="clearfix">
+				<span>报名信息</span>
+			</div>
+			<div v-for="(item, index) in activeItems" :key="index">
+			  <div class="picker-container" v-if="item.type == 1 || item.type == 2">
+			    <div class="label"><span v-if="item.isRequire">*</span>{{item.question}}({{{1: '单选', 2: '多选'}[item.type]}})</div>
+			    <div class="img-list" v-if="item.answer && item.answer.length > 0 && item.answer[0].option_files && item.answer[0].option_files.length > 0 && item.answer[0].option_files[0].url">
+			      <div
+			        class="item1"
+			        :class="it.active ? 'active' : ''"
+			        v-for="(it, idx) in item.answer"
+			        :key="idx"
+			        @click="clickOption(index, idx)">
+			        <el-image class="image" :src="it.option_files[0].url" mode="aspectFill"></el-image>
+			        <div class="text">{{it.option_value}}</div>
+			      </div>
+			    </div>
+			    <div class="text-list" v-else>
+			      <div
+			        class="item"
+			        :class="it.active ? 'active' : ''"
+			        v-for="(it, idx) in item.answer"
+			        :key="idx"
+			        @click="clickOption(index, idx)">
+			        {{it.option_value}}
+			      </div>
+			    </div>
+			  </div>
+			  <div class="input-container" v-else>
+			    <div class="label"><span v-if="item.isRequire">*</span>{{item.question}}</div>
+				<el-input type="text" v-model="item.inputValue" :maxlength="item.answer[0].option_limit" :disabled="formType!=0" :placeholder="`请输入${item.question}`"></el-input>
+			  </div>
+			</div>
+		</el-card>
+		<el-card class="box-card" v-if="formType != 0">
+			<div slot="header" class="clearfix">
+				<span>跟进记录</span>
+			</div>
+			<div class="mymain-container">
+				<el-form ref="formData" :model="formData" label-width="110px" size="small" label-position="left">
+					<el-row :gutter="20" justify="start">
+						<el-col :span="24">
+							<el-form-item label="最新跟进结果" prop="status" class="is-required">
+								<el-radio-group v-model="formData.status">
+								    <el-radio label="ING">继续跟进</el-radio>
+								    <el-radio label="END">无需跟进</el-radio>
+								</el-radio-group>
+							</el-form-item>
+						</el-col>
+						<el-col :span="24">
+							<el-form-item label="备注" prop="remark" :rules="[{ required: true, message: `请输入备注内容`, trigger: 'blur' }]">
+								<el-input type="textarea" :rows="3" v-model="formData.remark" placeholder="请输入"></el-input>
+							</el-form-item>
+						</el-col>
+					</el-row>
+				</el-form>
+			</div>
+			<div class="table">
+				<el-table :data="formData.records" element-loading-text="Loading" border fit highlight-current-row stripe>
+					<el-table-column prop="status" label="跟进结果" align="center">
+						<template slot-scope="scope">
+							{{scope.row.status == 'ING'?'继续跟进':scope.row.status == 'END'?'无需跟进':''}}
+						</template>
+					</el-table-column>
+					<el-table-column prop="remark" label="备注" align="center"></el-table-column>
+					<el-table-column prop="updateBy" align="center" label="跟进人" ></el-table-column>
+					<el-table-column prop="updateTime" align="center" label="跟进时间" ></el-table-column>
+				</el-table>
+			</div>
+		</el-card>
+		<div class="page-footer">
+			<div class="footer">
+				<el-button size="small" type="info" @click="goBack">返回</el-button>
+				<el-button v-if="formType == 0 || formData.status == 'ING'" size="small" type="primary" @click="submit()">提交</el-button>
+			</div>
+		</div>
+	</div>
+</template>
+
+<script>
+	import ImageUpload from '@/components/file-upload'
+	import { getDetail, add, follow, getActiveList, getActiveDetail } from "@/api/activityOrder";
+	export default {
+		components: {ImageUpload},
+		props: ['id','title','formType'],
+		data() {
+			return {
+				dataList: [],
+				activeList: [],
+				activeItems: [],
+				formData: {
+					active: {},
+					activeDate: [],
+					promotionActivityId: '',
+					userName: '',
+					linkName: '',
+					userMobile: '',
+					userMobile2: '',
+					userAddress: '',
+					
+				},
+				companyName: JSON.parse(localStorage.getItem('greemall_user')).companyName,
+				rules: {
+					userMobile: [
+						{ required: true, message: `请输入客户电话`, trigger: 'blur' },
+						{ required: true, message: `请输入客户电话`, trigger: 'change' },
+						{ pattern:/^((0\d{2,3}-\d{7,8})|(1[3456789]\d{9}))$/, message: '电话号码格式不正确', trigger: 'blur' }
+					],
+					userMobile2: [
+						{ required: true, message: '请输入客户电话或座机', trigger: 'blur' }
+					],
+					userName: [
+						{ required: true, message: '请输入客户名称', trigger: 'blur' }
+					],
+					linkName: [
+						{ required: true, message: '请输入联系人', trigger: 'blur' }
+					],
+					userAddress: [
+						{ required: true, message: '请输入客户地址', trigger: 'blur' }
+					],
+					promotionActivityId: [
+						{ required: true, message: '请选择活动名称', trigger: 'change' }
+					]
+				}
+			};
+		},
+		computed: {},
+		created() {
+			if(this.id){
+				this.getDetail()
+			}
+			this.getActiveList()
+		},
+		methods: {
+			// 返回
+			goBack() {
+				this.$emit('back');
+			},
+			async getDetail(){
+				const that = this
+				getDetail({promotionActivityId: this.id}).then( async res => {
+					Object.assign(this.formData, res.data)
+				})
+			},
+			getActiveList(){
+				getActiveList({}).then(res => {
+					this.activeList = res.data.records
+				})
+			},
+			getActiveDetail(id){
+				getActiveDetail({id}).then(res => {
+					res.data.promotionQuestionnaireItems.forEach(item=>{
+						item.answer = JSON.parse(item.answer)
+						item.inputValue = '';
+						item.answer.forEach(it => {
+						  it.active = false;
+						})
+					})
+					this.activeItems = res.data.promotionQuestionnaireItems
+				})
+			},
+			clickOption(index, idx) {
+			  // 单选题
+			  if(this.activeItems[index].type == 1) {
+			    this.activeItems[index].answer.forEach((item, ind_) => {
+			      this.activeItems[index].answer.splice(ind_, 1, {...item, active: ind_ == idx ? (this.activeItems[index].isRequire ? true : !item.active) : false})
+			    })
+			  }
+			  // 多选题
+			  else {
+			    this.activeItems[index].answer.splice(idx, 1, {...this.activeItems[index].answer[idx], active: !this.activeItems[index].answer[idx].active})
+			  }
+			},
+			submit(){
+				this.$refs.formData.validate((valid, invalidFields, errLabels) => {
+					if (valid) {
+						if(this.formType == 0){
+							for(let i = 0; i < this.activeItems.length; i++) {
+							  if(this.activeItems[i].isRequire) {
+							    // 单选题多选题
+							    if((this.activeItems[i].type == 1 || this.activeItems[i].type == 2) && this.activeItems[i].answer.every(o => !o.active)) {
+							      return this.$message.warning(`请选择${this.activeItems[i].question}`)
+							    }
+							    // 填写题
+							    if(this.activeItems[i].type == 3 && !this.activeItems[i].inputValue) {
+									return this.$message.warning(`请输入${this.activeItems[i].question}`)
+							    }
+							  }
+							}
+							// 生成题目提交信息
+							let items = [];
+							let activeItems = JSON.parse(JSON.stringify(this.activeItems));
+							for(let index = 0; index < activeItems.length; index++) {
+							  // 单选题多选题
+							  if ((activeItems[index].type == 1 || activeItems[index].type == 2) && activeItems[index].answer.some(o => o.active)) {
+							    activeItems[index].answer = activeItems[index].answer.filter(o => o.active);
+							    activeItems[index].answer = JSON.stringify(activeItems[index].answer);
+							    items.push(activeItems[index]);
+							  }
+							  // 填写题
+							  if (activeItems[index].type == 3 && activeItems[index].inputValue) {
+							    activeItems[index].answer[0].option_value = activeItems[index].inputValue;
+							    activeItems[index].answer = JSON.stringify(activeItems[index].answer);
+							    items.push(activeItems[index]);
+							  }
+							}
+							add({
+								promotionActivityId: this.formData.promotionActivityId,
+								userName: this.formData.userName,
+								linkName: this.formData.linkName,
+								userMobile: this.formData.userMobile,
+								userMobile2: this.formData.userMobile2,
+								userAddress: this.formData.userAddress,
+								items
+							}).then(res => {
+								if(res.code == 200){
+									this.$message.success('提交成功!')
+									this.goBack()
+								}
+							})
+						}else if(this.formType == 1){
+							follow({
+								ids: [this.id],
+								status: this.formData.status,
+								remark: this.formData.remark,
+							}).then(res => {
+								if(res.code == 200){
+									this.dataList = []
+									this.$message.success('提交成功!')
+									this.goBack()
+								}
+							})
+						}
+					}
+				})
+			}
+		}
+	};
+</script>
+
+<style scoped="scoped" lang="scss">
+	.s-page {
+		padding: 20px;
+		background-color: #ffffff;
+	}
+	.page-footer {
+		height: 70px;
+	}
+	.input-container {
+	  margin-top: 20px;
+	  .label {
+	    font-size: 14px;
+	    font-weight: bold;
+	    span {
+	      color: red;
+	    }
+	  }
+	}
+	.picker-container {
+	  margin-top: 20px;
+	  .label {
+	    font-size: 14px;
+	    font-weight: bold;
+	    span {
+	      color: red;
+	    }
+	  }
+	  .text-list {
+	    display: flex;
+	    flex-wrap: wrap;
+	    .item {
+	      margin-top: 20px;
+	      margin-right: 20px;
+	      height: 40px;
+	      border-radius: 30px;
+	      background: #f5f5f5;
+	      font-size: 14px;
+	      display: flex;
+	      align-items: center;
+	      justify-content: center;
+	      box-sizing: border-box;
+		  cursor: pointer;
+		  padding: 0 40px;
+	      &.active {
+	        border: 1px solid #f6390d;
+	        color: #f6390d;
+	        background: #ffffff;
+	      }
+	    }
+	  }
+	  .img-list {
+	    display: flex;
+	    flex-wrap: wrap;
+	    .item,.item1 {
+	      margin-top: 10px;
+	      margin-right: 10px;
+	      border-radius: 20px;
+		  height: 40px;
+	      display: flex;
+	      flex-direction: column;
+	      align-items: center;
+	      justify-content: center;
+	      box-sizing: border-box;
+	      padding: 0 40px;
+		  background-color: #f3f3f3;
+		  cursor: pointer;
+	      .image {
+	        width: 100%;
+	        height: 60px;
+	      }
+	      .text {
+	        font-size: 14px;
+	      }
+	      &.active {
+	        border: 1px solid #f6390d;
+			background-color: #ffffff;
+	        .text {
+	          color: #f6390d;
+	        }
+	      }
+	    }
+		.item1{
+			height: 130px;
+			border-radius: 6px;
+			padding: 6px;
+			.image {
+			  width: 120px;
+			  height: 100px;
+			}
+		}
+	  }
+	}
+	.footer {
+		position: fixed;
+		bottom: 0;
+		left: 0;
+		z-index: 1;
+		width: 100%;
+		background: #fff;
+		padding: 15px 40px;
+		box-sizing: border-box;
+		transition: all 0.28s;
+		text-align: right;
+		box-shadow: 0 2px 5px 0 rgb(0 0 0 / 50%), 0 2px 5px 0 rgb(0 0 0 / 10%);
+	
+		&.hideSidebar {
+			margin-left: 54px;
+			width: calc(100vw - 54px);
+		}
+	
+		&.openSidebar {
+			margin-left: 210px;
+			width: calc(100vw - 210px);
+		}
+	
+		.tips {
+			font-size: 12px;
+			color: red;
+			margin-top: 10px;
+		}
+	}
+</style>

+ 225 - 0
src/views/mallManagement/activityOrder/index.vue

@@ -0,0 +1,225 @@
+<template>
+	<div class="page">
+		<template-page v-if="!formDialog" ref="pageRef" :get-list="getList" :table-attributes="tableAttributes"
+			:table-events="tableEvents" :operationColumnWidth="80" :options-evens-group="optionsEvensGroup"
+			:moreParameters="moreParameters" :column-parsing="columnParsing" :operation="operation()" :exportList="exportList">
+			<div slot="moreSearch">
+				<el-radio-group v-model="status" size="mini" @change="changeType">
+					<el-radio-button label="ING">继续跟进</el-radio-button>
+					<el-radio-button label="END">无需跟进</el-radio-button>
+					<el-radio-button label="">全部</el-radio-button>
+				</el-radio-group>
+				<br><br>
+			</div>
+		</template-page>
+		<div class="detail" v-if="formDialog">
+			<detail :id="id" @back="backList" :formType="formDialogType" :title="'活动单' + formDialogTitles[formDialogType]"></detail>
+		</div>
+		<!-- 选择商品 -->
+		<el-dialog title="批量跟进" :visible.sync="isShow" width="50%" :close-on-click-modal="false" :modal-append-to-body="false" @close="formData = {status: 'END',remark: ''}">
+			<el-form ref="formData" :model="formData" label-width="110px" size="small" label-position="left">
+				<el-row :gutter="20" justify="start">
+					<el-col :span="24">
+						<el-form-item label="最新跟进结果" prop="status" :required="true">
+							<el-radio-group v-model="formData.status">
+							    <el-radio label="ING">继续跟进</el-radio>
+							    <el-radio label="END">无需跟进</el-radio>
+							</el-radio-group>
+						</el-form-item>
+					</el-col>
+					<el-col :span="24">
+						<el-form-item label="备注" prop="remark" :rules="[{ required: true, message: `请输入备注内容`, trigger: 'blur' }]">
+							<el-input type="textarea" :rows="3" v-model="formData.remark" placeholder="请输入"></el-input>
+						</el-form-item>
+					</el-col>
+				</el-row>
+			</el-form>
+			<div class="footer">
+				<el-button size="mini" @click="isShow = false">取消</el-button>
+				<el-button size="mini" @click="formConfirm()" type="primary">确定</el-button>
+			</div>
+		</el-dialog>
+	</div>
+</template>
+
+<script>
+import TemplatePage from '@/components/template/template-page-1.vue'
+import detail from './detail.vue'
+import import_mixin from '@/components/template/import_mixin.js'
+import ImageUpload from '@/components/file-upload'
+import { downloadFiles } from '@/utils/util'
+import { required, mobileRequired, mobile, httpUrl, email } from '@/components/template/rules_verify.js'
+import { listPageV2, pageExport, getDetail, add, follow } from "@/api/activityOrder";
+import operation_mixin from '@/components/template/operation_mixin.js'
+export default {
+	components: { TemplatePage, ImageUpload, detail },
+	mixins: [import_mixin, operation_mixin],
+	data() {
+		return {
+			// 表格属性
+			tableAttributes: {
+				// 启用勾选列
+				selectColumn: true
+			},
+			// 表格事件
+			tableEvents: {
+				'selection-change': this.selectionChange
+			},
+			// 勾选选中行
+			recordSelected: [],
+			/** 表单变量 */
+			formDialogType: 0,
+			formDialogTitles: ["新增", "编辑", "详情"],
+			formDialog: false,
+			status: 'ING',
+			id: '',
+			isShow: false,
+			formData: {
+				status: 'END',
+				remark: ''
+			}
+		}
+	},
+	computed: {
+		// 事件组合
+		optionsEvensGroup() {
+			return [
+				[
+					[
+						this.optionsEvensAuth("add", {
+							click: this.addData
+						}),
+					]
+				],
+				[
+					[
+						this.optionsEvensAuth("followUpMore", {
+							click: this.followMore
+						}),
+					]
+				],
+			]
+		},
+		// 更多参数
+		moreParameters() {
+			return []
+		},
+		formItems() { },
+	},
+	created(){
+		
+	},
+	methods: {
+		// 切换状态
+		changeType(val) {
+			this.$refs.pageRef.refreshList()
+		},
+		backList() {
+			this.id = ''
+			this.formDialog = false;
+			this.$refs.pageRef.refreshList()
+		},
+		// 列表请求函数
+		getList(p, cb) {
+			try {
+				var pam = JSON.parse(JSON.stringify(p))
+				pam.params.push({ "param": "a.status", "compare": "=", "value": this.status })
+				cb && cb(pam)
+				return listPageV2(pam)
+			} catch (error) {
+				console.log(error)
+			}
+		},
+		// 列表导出函数
+		exportList: pageExport,
+		// 表格列解析渲染数据更改
+		columnParsing(item, defaultData) {
+			return defaultData
+		},
+		// 监听勾选变化
+		selectionChange(data) {
+			this.recordSelected = data
+		},
+
+		operation() {
+			return this.operationBtn({
+				followUp: {
+					conditions: ({ row, index, column }) => {
+						return row.status == 'ING'
+					},
+					click: ({ row, index, column }) => {
+						this.id = row.promotionActivityId
+						this.formDialogType = 1
+						this.openForm()
+					}
+				},
+				detail: {
+					click: ({ row, index, column }) => {
+						this.id = row.promotionActivityId
+						this.formDialogType = 2
+						this.openForm()
+					}
+				}
+			})
+		},
+
+		addData() {
+			this.formDialogType = 0
+			this.openForm()
+		},
+		openForm() {
+			this.formDialog = true;
+		},
+		followMore() {
+			if (this.recordSelected.length == 0) {
+				return this.$message.warning('请至少勾选一条数据!');
+			}
+			this.isShow = true
+		},
+		formConfirm() {
+			let ids = this.recordSelected.map(item => { return item.promotionActivityId })
+			this.$refs.formData.validate((valid, invalidFields, errLabels) => {
+				if (valid) {
+					this.$confirm('请确认是否批量跟进选中的数据, 是否继续?', '提示', {
+						confirmButtonText: '确定',
+						cancelButtonText: '取消',
+						type: 'warning'
+					}).then(() => {
+						follow({
+							ids,
+							status: this.formData.status,
+							remark: this.formData.remark
+						}).then(res => {
+							this.isShow = false
+							this.$refs?.formData?.resetFields()
+							this.$message({ type: 'success', message: '批量跟进成功!' })
+							this.$refs.pageRef.refreshList()
+						})
+					});
+				}
+			})	
+		},
+	}
+}
+</script>
+
+<style lang="scss" scoped>
+.page {
+	height: 100%;
+}
+
+.tab {
+	padding: 20px 20px 0 20px;
+}
+
+.importResultList {
+	.item {
+		font-size: 16px;
+		margin-bottom: 10px;
+	}
+}
+.footer{
+	display: flex;
+	justify-content: flex-end;
+}
+</style>