detail.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  1. <template>
  2. <div class="s-page">
  3. <el-page-header @back="goBack" :content="title"></el-page-header>
  4. <el-divider></el-divider>
  5. <el-card class="box-card">
  6. <div slot="header" class="clearfix">
  7. <span>基本信息</span>
  8. </div>
  9. <div class="mymain-container">
  10. <el-form ref="formData" :rules="rules" :model="formData" label-width="110px" size="small" label-position="left">
  11. <el-row :gutter="20" justify="start">
  12. <el-col :span="6">
  13. <el-form-item label="所属商户" :required="true">
  14. <el-input
  15. type="text"
  16. :value="formData.companyWechatName ? formData.companyWechatName : companyName"
  17. disabled
  18. ></el-input>
  19. </el-form-item>
  20. </el-col>
  21. <el-col :span="6" style="height: 51px">
  22. <el-form-item label="活动名称" prop="promotionActivityId">
  23. <el-select
  24. v-model="formData.active"
  25. :disabled="formType != 0"
  26. value-key="id"
  27. @change="
  28. e => {
  29. formData.promotionActivityId = e.id
  30. formData.activeDate = [e.startTime, e.endTime]
  31. this.getActiveDetail(e.id)
  32. }
  33. "
  34. placeholder="请选择"
  35. style="width: 100%"
  36. >
  37. <el-option v-for="item in activeList" :key="item.id" :label="item.name" :value="item"> </el-option>
  38. </el-select>
  39. </el-form-item>
  40. </el-col>
  41. <el-col :span="6" style="height: 51px">
  42. <el-form-item label="活动网点" prop="customWebsitName">
  43. <el-select
  44. v-model="formData.customWebsitName"
  45. :disabled="formType != 0"
  46. placeholder="请选择"
  47. style="width: 100%"
  48. >
  49. <el-option
  50. v-for="(item, index) in websitList"
  51. :key="index"
  52. :label="item.websitName"
  53. :value="item.websitName"
  54. >
  55. </el-option>
  56. </el-select>
  57. </el-form-item>
  58. </el-col>
  59. <el-col :span="6" style="margin-bottom: 1px">
  60. <el-form-item label="活动时间" prop="" class="is-required">
  61. <el-date-picker
  62. style="width: 100%"
  63. v-model="formData.activeDate"
  64. disabled
  65. type="daterange"
  66. range-separator="至"
  67. start-placeholder="开始日期"
  68. end-placeholder="结束日期"
  69. >
  70. </el-date-picker>
  71. </el-form-item>
  72. </el-col>
  73. <el-col :span="6">
  74. <el-form-item label="客户名称" prop="userName">
  75. <el-input
  76. type="text"
  77. :disabled="formType != 0"
  78. v-model="formData.userName"
  79. placeholder="请输入"
  80. ></el-input>
  81. </el-form-item>
  82. </el-col>
  83. <el-col :span="6">
  84. <el-form-item label="联系人" prop="linkName">
  85. <el-input
  86. type="text"
  87. :disabled="formType != 0"
  88. v-model="formData.linkName"
  89. placeholder="请输入"
  90. ></el-input>
  91. </el-form-item>
  92. </el-col>
  93. <el-col :span="6">
  94. <el-form-item label="客户电话" prop="userMobile">
  95. <el-input
  96. type="text"
  97. :disabled="formType != 0"
  98. :maxlength="11"
  99. v-model="formData.userMobile"
  100. placeholder="请输入"
  101. ></el-input>
  102. </el-form-item>
  103. </el-col>
  104. <el-col :span="6">
  105. <el-form-item label="客户电话2" prop="userMobile2">
  106. <el-input
  107. type="text"
  108. :disabled="formType != 0"
  109. v-model="formData.userMobile2"
  110. placeholder="请输入电话 (固话加区号)"
  111. ></el-input>
  112. </el-form-item>
  113. </el-col>
  114. <el-col :span="24">
  115. <el-form-item label="客户地址" prop="userAddress">
  116. <el-input
  117. type="text"
  118. v-model="formData.userAddress"
  119. :disabled="formType != 0"
  120. placeholder="详细地址"
  121. ></el-input>
  122. </el-form-item>
  123. </el-col>
  124. <template v-if="formType != 0">
  125. <el-col :span="6">
  126. <el-form-item label="提交人" prop="createBy">
  127. <el-input type="text" v-model="formData.createBy" :disabled="true" placeholder="提交人"></el-input>
  128. </el-form-item>
  129. </el-col>
  130. <el-col :span="6">
  131. <el-form-item label="提交时间" prop="createTime">
  132. <el-input
  133. type="text"
  134. v-model="formData.createTime"
  135. :disabled="true"
  136. placeholder="提交时间"
  137. ></el-input>
  138. </el-form-item>
  139. </el-col>
  140. </template>
  141. </el-row>
  142. </el-form>
  143. </div>
  144. </el-card>
  145. <el-card class="box-card" v-if="activeItems.length > 0">
  146. <div slot="header" class="clearfix">
  147. <span>报名信息</span>
  148. </div>
  149. <div v-for="(item, index) in activeItems" :key="index">
  150. <div class="picker-container" v-if="item.type == 1 || item.type == 2">
  151. <div class="label">
  152. <span v-if="item.isRequire">*</span>{{ item.question }}({{ { 1: '单选', 2: '多选' }[item.type] }})
  153. </div>
  154. <div
  155. class="img-list"
  156. v-if="
  157. item.answer &&
  158. item.answer.length > 0 &&
  159. item.answer[0].option_files &&
  160. item.answer[0].option_files.length > 0 &&
  161. item.answer[0].option_files[0].url
  162. "
  163. >
  164. <div
  165. class="item1"
  166. :class="it.active ? 'active' : ''"
  167. v-for="(it, idx) in item.answer"
  168. :key="idx"
  169. @click="clickOption(index, idx)"
  170. >
  171. <el-image
  172. v-if="item.answerType != 2"
  173. class="image"
  174. :src="$showImgUrl(returnUrl(it))"
  175. mode="aspectFill"
  176. ></el-image>
  177. <div class="text" v-if="item.answerType != 3">{{ it.option_value }}</div>
  178. </div>
  179. </div>
  180. <div class="text-list" v-else>
  181. <div
  182. class="item"
  183. :class="it.active ? 'active' : ''"
  184. v-for="(it, idx) in item.answer"
  185. :key="idx"
  186. @click="clickOption(index, idx)"
  187. >
  188. {{ it.option_value }}
  189. </div>
  190. </div>
  191. </div>
  192. <div class="input-container" v-else-if="item.type == 3">
  193. <div class="label"><span v-if="item.isRequire">*</span>{{ item.question }}</div>
  194. <el-input
  195. type="text"
  196. v-model="item.inputValue"
  197. show-word-limit
  198. :maxlength="item.answer[0].option_limit"
  199. :disabled="formType != 0"
  200. :placeholder="`请输入${item.question}`"
  201. ></el-input>
  202. </div>
  203. <div class="input-container" v-else-if="item.type == 4">
  204. <div class="label"><span v-if="item.isRequire">*</span>{{ item.question }}</div>
  205. <br />
  206. <ImageUpload
  207. :fileList="item.inputValue"
  208. :limit="Number(item.answer[0].option_limit)"
  209. :isEdit="formType == 0"
  210. :fileType="['image']"
  211. />
  212. </div>
  213. <div class="input-container" v-else>
  214. <div class="label"><span v-if="item.isRequire">*</span>{{ item.question }}</div>
  215. <br />
  216. <ImageUpload
  217. :fileList="item.inputValue"
  218. :limit="Number(item.answer[0].option_limit)"
  219. :isEdit="formType == 0"
  220. :fileType="['video']"
  221. />
  222. </div>
  223. </div>
  224. </el-card>
  225. <el-card class="box-card" v-if="formType != 0">
  226. <div slot="header" class="clearfix">
  227. <span>跟进记录</span>
  228. </div>
  229. <div class="mymain-container">
  230. <el-form ref="formData" :model="formData" label-width="110px" size="small" label-position="left">
  231. <el-row :gutter="20" justify="start">
  232. <el-col :span="24">
  233. <el-form-item label="最新跟进结果" prop="status" class="is-required">
  234. <el-radio-group v-model="formData.status">
  235. <el-radio :disabled="status == 'END'" label="ING">继续跟进</el-radio>
  236. <el-radio :disabled="status == 'END'" label="END">无需跟进</el-radio>
  237. </el-radio-group>
  238. </el-form-item>
  239. </el-col>
  240. <el-col :span="24">
  241. <el-form-item
  242. label="备注"
  243. prop="remark"
  244. :rules="[{ required: true, message: `请输入备注内容`, trigger: 'blur' }]"
  245. >
  246. <el-input
  247. type="textarea"
  248. :rows="3"
  249. :disabled="status == 'END'"
  250. v-model="formData.remark"
  251. placeholder="请输入"
  252. ></el-input>
  253. </el-form-item>
  254. </el-col>
  255. </el-row>
  256. </el-form>
  257. </div>
  258. <div class="table">
  259. <div>跟进记录</div>
  260. <br />
  261. <el-table :data="formData.records" element-loading-text="Loading" border fit highlight-current-row stripe>
  262. <el-table-column prop="status" label="跟进结果" align="center">
  263. <template slot-scope="scope">
  264. {{ scope.row.status == 'ING' ? '继续跟进' : scope.row.status == 'END' ? '无需跟进' : '' }}
  265. </template>
  266. </el-table-column>
  267. <el-table-column prop="remark" label="备注" align="center"></el-table-column>
  268. <el-table-column prop="createBy" align="center" label="跟进人"></el-table-column>
  269. <el-table-column prop="createTime" align="center" label="跟进时间"></el-table-column>
  270. </el-table>
  271. </div>
  272. </el-card>
  273. <div class="page-footer">
  274. <div class="footer">
  275. <el-button size="small" type="info" @click="goBack">返回</el-button>
  276. <el-button v-if="formType == 0 || status == 'ING'" size="small" type="primary" @click="submit()"
  277. >提交</el-button
  278. >
  279. </div>
  280. </div>
  281. </div>
  282. </template>
  283. <script>
  284. import ImageUpload from '@/components/file-upload'
  285. import { getDetail, add, follow, getActiveList, getActiveDetail } from '@/api/activityOrder'
  286. export default {
  287. components: { ImageUpload },
  288. props: ['id', 'title', 'formType', 'activeId'],
  289. data() {
  290. return {
  291. dataList: [],
  292. activeList: [],
  293. activeItems: [],
  294. websitList: [],
  295. formData: {
  296. active: {},
  297. activeDate: [],
  298. promotionActivityId: '',
  299. customWebsitName: '',
  300. userName: '',
  301. linkName: '',
  302. userMobile: '',
  303. userMobile2: '',
  304. userAddress: '',
  305. status: '',
  306. remark: ''
  307. },
  308. status: '',
  309. companyName: JSON.parse(localStorage.getItem('greemall_user')).companyName,
  310. rules: {
  311. userMobile: [
  312. { required: true, message: `请输入客户电话`, trigger: 'blur' },
  313. { required: true, message: `请输入客户电话`, trigger: 'change' },
  314. { pattern: /^((0\d{2,3}-\d{7,8})|(1[3456789]\d{9}))$/, message: '电话号码格式不正确', trigger: 'blur' }
  315. ],
  316. userName: [{ required: true, message: '请输入客户名称', trigger: 'blur' }],
  317. linkName: [{ required: true, message: '请输入联系人', trigger: 'blur' }],
  318. userAddress: [{ required: true, message: '请输入客户地址', trigger: 'blur' }],
  319. promotionActivityId: [{ required: true, message: '请选择活动名称', trigger: 'change' }]
  320. }
  321. }
  322. },
  323. computed: {
  324. returnUrl() {
  325. return function (it) {
  326. return it.option_files.length > 0 ? it.option_files[0].url : ''
  327. }
  328. }
  329. },
  330. created() {
  331. if (this.id) {
  332. this.getDetail()
  333. }
  334. if (this.activeId) {
  335. this.formData.active = { id: this.activeId }
  336. this.formData.promotionActivityId = this.activeId
  337. if (this.formType == 0) {
  338. this.getActiveDetail(this.activeId)
  339. }
  340. }
  341. this.getActiveList()
  342. },
  343. methods: {
  344. // 返回
  345. goBack() {
  346. this.$emit('back')
  347. },
  348. async getDetail() {
  349. const that = this
  350. getDetail({ promotionActivityId: this.id }).then(async res => {
  351. Object.assign(this.formData, res.data, {
  352. active: { id: res.data.promotionQuestionnaireId }
  353. })
  354. this.websitList = res.data.promotionQuestionnaireQrcodes
  355. this.status = res.data.status
  356. res.data.items.forEach(item => {
  357. item.answer = JSON.parse(item.answer)
  358. item.answer.forEach(it => {
  359. if (item.type == 3) {
  360. item.inputValue = it.option_value
  361. } else if (item.type == 4 || item.type == 5) {
  362. let img = []
  363. it.option_value.forEach(t => {
  364. img.push({ url: t })
  365. })
  366. console.log(it.option_value, img)
  367. item.inputValue = img
  368. }
  369. })
  370. })
  371. this.activeItems = res.data.items
  372. getActiveDetail({ id: res.data.promotionQuestionnaireId }).then(res => {
  373. this.formData.activeDate = [res.data.startTime, res.data.endTime]
  374. })
  375. // this.getActiveDetail(res.data.promotionQuestionnaireId,res.data.items)
  376. })
  377. },
  378. getActiveList() {
  379. getActiveList({ pageNum: 1, pageSize: -1, status: 1 }).then(res => {
  380. this.activeList = res.data.records
  381. })
  382. },
  383. getActiveDetail(id, items) {
  384. getActiveDetail({ id }).then(res => {
  385. this.formData.activeDate = [res.data.startTime, res.data.endTime]
  386. this.websitList = res.data.promotionQuestionnaireQrcodes
  387. res.data.promotionQuestionnaireItems.forEach((item, index) => {
  388. item.answer = JSON.parse(item.answer)
  389. if (items) {
  390. item.answer.forEach(it1 => {
  391. items.forEach(it2 => {
  392. JSON.parse(it2.answer).forEach(t => {
  393. if (item.id == it2.id && t.active && it1.option_value == t.option_value) {
  394. console.log(t.option_value)
  395. it1.active = true
  396. }
  397. if (it2.type == 3) {
  398. item.inputValue = t.option_value
  399. } else if (it2 == 4 || it2 == 5) {
  400. item.inputValue = [{ url: t.option_value }]
  401. }
  402. })
  403. })
  404. })
  405. } else {
  406. if (item.type == 4 || item.type == 5) {
  407. item.inputValue = []
  408. } else {
  409. item.inputValue = ''
  410. }
  411. item.answer.forEach(it => {
  412. it.active = false
  413. })
  414. }
  415. })
  416. this.activeItems = res.data.promotionQuestionnaireItems
  417. console.log(this.activeItems, 111)
  418. })
  419. },
  420. clickOption(index, idx) {
  421. if (this.id) {
  422. return false
  423. }
  424. // 单选题
  425. if (this.activeItems[index].type == 1) {
  426. this.activeItems[index].answer.forEach((item, ind_) => {
  427. this.activeItems[index].answer.splice(ind_, 1, {
  428. ...item,
  429. active: ind_ == idx ? (this.activeItems[index].isRequire ? true : !item.active) : false
  430. })
  431. })
  432. }
  433. // 多选题
  434. else {
  435. this.activeItems[index].answer.splice(idx, 1, {
  436. ...this.activeItems[index].answer[idx],
  437. active: !this.activeItems[index].answer[idx].active
  438. })
  439. }
  440. },
  441. submit() {
  442. this.$refs.formData.validate((valid, invalidFields, errLabels) => {
  443. if (valid) {
  444. if (this.formType == 0) {
  445. for (let i = 0; i < this.activeItems.length; i++) {
  446. if (this.activeItems[i].isRequire) {
  447. // 单选题多选题
  448. if (
  449. (this.activeItems[i].type == 1 || this.activeItems[i].type == 2) &&
  450. this.activeItems[i].answer.every(o => !o.active)
  451. ) {
  452. return this.$message.warning(`请选择${this.activeItems[i].question}`)
  453. }
  454. // 填写题
  455. if (this.activeItems[i].type == 3 && !this.activeItems[i].inputValue) {
  456. return this.$message.warning(`请输入${this.activeItems[i].question}`)
  457. }
  458. // 图片视频
  459. if (
  460. (this.activeItems[i].type == 4 || this.activeItems[i].type == 5) &&
  461. this.activeItems[i].inputValue.length == 0
  462. ) {
  463. return this.$message.warning(`请上传${this.activeItems[i].question}`)
  464. }
  465. }
  466. }
  467. // 生成题目提交信息
  468. let items = []
  469. let activeItems = JSON.parse(JSON.stringify(this.activeItems))
  470. for (let index = 0; index < activeItems.length; index++) {
  471. // 单选题多选题
  472. if (activeItems[index].type == 1 || activeItems[index].type == 2) {
  473. // activeItems[index].answer = activeItems[index].answer.filter(o => o.active);
  474. activeItems[index].answer = JSON.stringify(activeItems[index].answer)
  475. items.push(activeItems[index])
  476. }
  477. // 填写题
  478. if (activeItems[index].type == 3) {
  479. activeItems[index].answer[0].option_value = activeItems[index].inputValue
  480. activeItems[index].answer = JSON.stringify(activeItems[index].answer)
  481. items.push(activeItems[index])
  482. }
  483. // 图片视频
  484. if (activeItems[index].type == 4 || activeItems[index].type == 5) {
  485. let option_value = []
  486. activeItems[index].inputValue.forEach(item => {
  487. option_value.push(item.url)
  488. })
  489. activeItems[index].answer[0].option_value = option_value
  490. activeItems[index].answer = JSON.stringify(activeItems[index].answer)
  491. items.push(activeItems[index])
  492. }
  493. }
  494. add({
  495. promotionQuestionnaireId: this.formData.promotionActivityId,
  496. userName: this.formData.userName,
  497. linkName: this.formData.linkName,
  498. userMobile: this.formData.userMobile,
  499. userMobile2: this.formData.userMobile2,
  500. userAddress: this.formData.userAddress,
  501. customWebsitName: this.formData.customWebsitName,
  502. items
  503. }).then(res => {
  504. if (res.code == 200) {
  505. this.$message.success('提交成功!')
  506. this.goBack()
  507. }
  508. })
  509. } else {
  510. follow({
  511. ids: [this.id],
  512. status: this.formData.status,
  513. remark: this.formData.remark
  514. }).then(res => {
  515. if (res.code == 200) {
  516. this.dataList = []
  517. this.$message.success('提交成功!')
  518. this.goBack()
  519. }
  520. })
  521. }
  522. }
  523. })
  524. }
  525. }
  526. }
  527. </script>
  528. <style scoped="scoped" lang="scss">
  529. .s-page {
  530. padding: 20px;
  531. background-color: #ffffff;
  532. }
  533. .page-footer {
  534. height: 70px;
  535. }
  536. .input-container {
  537. margin-top: 20px;
  538. .label {
  539. font-size: 14px;
  540. font-weight: bold;
  541. span {
  542. color: red;
  543. }
  544. }
  545. }
  546. .picker-container {
  547. margin-top: 20px;
  548. .label {
  549. font-size: 14px;
  550. font-weight: bold;
  551. span {
  552. color: red;
  553. }
  554. }
  555. .text-list {
  556. display: flex;
  557. flex-wrap: wrap;
  558. .item {
  559. margin-top: 20px;
  560. margin-right: 20px;
  561. height: 40px;
  562. border-radius: 30px;
  563. background: #f5f5f5;
  564. font-size: 14px;
  565. display: flex;
  566. align-items: center;
  567. justify-content: center;
  568. box-sizing: border-box;
  569. cursor: pointer;
  570. padding: 0 40px;
  571. &.active {
  572. border: 1px solid #f6390d;
  573. color: #f6390d;
  574. background: #ffffff;
  575. }
  576. }
  577. }
  578. .img-list {
  579. display: flex;
  580. flex-wrap: wrap;
  581. .item,
  582. .item1 {
  583. margin-top: 10px;
  584. margin-right: 10px;
  585. border-radius: 20px;
  586. height: 40px;
  587. display: flex;
  588. flex-direction: column;
  589. align-items: center;
  590. justify-content: center;
  591. box-sizing: border-box;
  592. padding: 0 40px;
  593. background-color: #f3f3f3;
  594. cursor: pointer;
  595. .image {
  596. width: 100%;
  597. height: 60px;
  598. }
  599. .text {
  600. font-size: 14px;
  601. }
  602. &.active {
  603. border: 1px solid #f6390d;
  604. background-color: #ffffff;
  605. .text {
  606. color: #f6390d;
  607. }
  608. }
  609. }
  610. .item1 {
  611. height: 130px;
  612. border-radius: 6px;
  613. padding: 6px;
  614. .image {
  615. width: 120px;
  616. height: 100px;
  617. }
  618. }
  619. }
  620. }
  621. .footer {
  622. position: fixed;
  623. bottom: 0;
  624. left: 0;
  625. z-index: 1;
  626. width: 100%;
  627. background: #fff;
  628. padding: 15px 40px;
  629. box-sizing: border-box;
  630. transition: all 0.28s;
  631. text-align: right;
  632. box-shadow: 0 2px 5px 0 rgb(0 0 0 / 50%), 0 2px 5px 0 rgb(0 0 0 / 10%);
  633. &.hideSidebar {
  634. margin-left: 54px;
  635. width: calc(100vw - 54px);
  636. }
  637. &.openSidebar {
  638. margin-left: 210px;
  639. width: calc(100vw - 210px);
  640. }
  641. .tips {
  642. font-size: 12px;
  643. color: red;
  644. margin-top: 10px;
  645. }
  646. }
  647. </style>