index.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596
  1. <template>
  2. <template-page ref="pageRef" :get-list="getList" :exportList="exportList" :table-attributes="tableAttributes"
  3. :table-events="tableEvents" :options-evens-group="optionsEvensGroup"
  4. :column-parsing="columnParsing" :operation="operation()" :operationColumnWidth="200">
  5. <div class="cartographer">
  6. <el-dialog :title="formData.id?'详情':'新增'" width="100%" :modal="false" :visible.sync="formDialog"
  7. :before-close="formCancel">
  8. <zj-form-container v-if="formDialog" ref="formRef" :form-data="formData" :styleSwitch="false">
  9. <zj-form-module title="活动信息" label-width="120px" :form-data="formData"
  10. :form-items="formItems">
  11. </zj-form-module>
  12. <zj-form-module title="活动填写内容" label-width="100px" :form-data="formData"
  13. :form-items="formItems2">
  14. </zj-form-module>
  15. </zj-form-container>
  16. <div slot="footer" class="dialog-footer">
  17. <el-button size="mini" @click="formCancel">取 消</el-button>
  18. <el-button v-if="!formData.id" size="mini" type="primary" @click="formConfirm">确 定</el-button>
  19. <el-button v-if="formData.id && !!~[0, 1].indexOf(formData.status)" size="mini" type="primary" @click="zhongzhi">终 止</el-button>
  20. </div>
  21. </el-dialog>
  22. </div>
  23. <answer v-if="showQuestion" :defaultData="questionData" @close="questionClose" @confirm="questionConfirm"/>
  24. </template-page>
  25. </template>
  26. <script>
  27. import TemplatePage from '@/components/template/template-page-1.vue'
  28. import import_mixin from '@/components/template/import_mixin.js'
  29. import operation_mixin from '@/components/template/operation_mixin.js'
  30. import {promotionQuestionnaireList,promotionQuestionnaireExport,promotionQuestionnaireAdd,promotionQuestionnaireStop,promotionQuestionnaireDetail} from "@/api/setActivity.js"
  31. import answer from "./answer.vue"
  32. import ImageUpload from '@/components/file-upload'
  33. import quillEditor from '@/components/v-quill-editor'
  34. import editTable from "@/components/template/editTable.js"
  35. import { required, mobileRequired, mobile, httpUrl, email } from '@/components/template/rules_verify.js'
  36. export default {
  37. components: { TemplatePage, answer, ImageUpload, quillEditor },
  38. mixins: [import_mixin, operation_mixin, editTable],
  39. data() {
  40. return {
  41. formDialog: false,
  42. showQuestion: false,
  43. questionData: {
  44. rowIndex: -1
  45. },
  46. formData: {
  47. "companyWechatId": "",
  48. "companyWechatName": JSON.parse(localStorage.getItem('greemall_user')).companyName,
  49. "startTime": "",
  50. "endTime": "",
  51. "name": "",
  52. "submitLimit": '',
  53. "submitLimitBool": 0,
  54. "qrcode": "",
  55. "title": "",
  56. "content": "",
  57. "banner": [],
  58. "detailImgs": [],
  59. "promotionQuestionnaireItems": [],
  60. "promotionQuestionnaireUsers": [],
  61. },
  62. // 表格属性
  63. tableAttributes: {
  64. // 启用勾选列
  65. selectColumn: false
  66. },
  67. // 表格事件
  68. tableEvents: {},
  69. }
  70. },
  71. computed:{
  72. // 事件组合
  73. optionsEvensGroup() {
  74. return [
  75. [
  76. [
  77. this.optionsEvensAuth('add', {
  78. click: this.addData
  79. })
  80. ]
  81. ]
  82. ]
  83. },
  84. formItems(){
  85. return [
  86. {
  87. name: 'el-input',
  88. md: 12,
  89. attributes: { disabled: true, placeholder: '请选择' },
  90. formItemAttributes: { label: '所属商户', prop: 'companyWechatName' }
  91. },
  92. {
  93. name: 'el-date-picker',
  94. md: 6,
  95. attributes: {
  96. disabled: !!this.formData.id,
  97. style: { width: '100%' },
  98. placeholder: '请选择',
  99. 'value-format': 'yyyy-MM-dd HH:mm:ss',
  100. },
  101. formItemAttributes: {
  102. label: '活动开始日期',
  103. prop: 'startTime',
  104. rules: [{ required: true, message: '请选择', trigger: 'blur' }]
  105. }
  106. },
  107. {
  108. name: 'el-date-picker',
  109. md: 6,
  110. attributes: {
  111. disabled: !!this.formData.id,
  112. style: { width: '100%' },
  113. placeholder: '请选择',
  114. 'value-format': 'yyyy-MM-dd HH:mm:ss',
  115. },
  116. formItemAttributes: {
  117. label: '活动结束日期',
  118. prop: 'endTime',
  119. rules: [{ required: true, message: '请选择', trigger: 'blur' }]
  120. }
  121. },
  122. {
  123. name: 'el-input',
  124. md: 12,
  125. attributes: { disabled: !!this.formData.id, placeholder: '请选择' },
  126. formItemAttributes: {
  127. label: '活动名称',
  128. prop: 'name',
  129. rules: [{ required: true, message: '请填写', trigger: 'blur' }]
  130. }
  131. },
  132. {
  133. name: 'el-input',
  134. md: 12,
  135. attributes: { disabled: !!this.formData.id, placeholder: '请选择', maxlength:8 },
  136. formItemAttributes: {
  137. label: '二维码主题',
  138. prop: 'title',
  139. rules: [{ required: true, message: '请填写', trigger: 'blur' }]
  140. }
  141. },
  142. {
  143. md: 24,
  144. name: 'slot-component',
  145. attributes: { placeholder: '请输入' },
  146. formItemAttributes: {
  147. label: '提交次数',
  148. prop: 'submitLimitBool',
  149. rules: [{ required: true, message: '请选择', trigger: 'blur' }]
  150. },
  151. render: (h, { props, onInput }) => {
  152. var { value } = props
  153. console.log(value)
  154. return (
  155. <div class="redbordererr" style="">
  156. <el-form-item label="" label-width="0px" prop="submitLimit" rules={value ? [{ required: true, message: '请填写', trigger: 'blur' }] : []}>
  157. <el-radio-group disabled={!!this.formData.id} value={value} onInput={onInput}>
  158. <el-radio disabled={!!this.formData.id} label={0}>不限制</el-radio>
  159. <el-radio disabled={!!this.formData.id} label={1}>
  160. 限制{value?[<el-input disabled={!!this.formData.id} style="margin: 0 10px;width:100px;" value={this.formData.submitLimit} onInput={(val)=>{this.formData.submitLimit = val}} type="number" placeholder="请输入内容"></el-input>,<span>次</span>]:null}
  161. </el-radio>
  162. </el-radio-group>
  163. </el-form-item>
  164. </div>
  165. )
  166. }
  167. },
  168. {
  169. md: 24,
  170. name: 'slot-component',
  171. attributes: { placeholder: '请输入' },
  172. formItemAttributes: {
  173. label: '首页广告图',
  174. prop: 'banner',
  175. rules: [{ required: true, message: '请上传', trigger: 'blur' }]
  176. },
  177. render: (h, { props, onInput }) => {
  178. var { value } = props
  179. return (
  180. <ImageUpload isEdit={!this.formData.id} fileList={this.formData.banner} uid={`questionFiles_bananner`} limit={1} isUpdate={false} />
  181. )
  182. }
  183. },
  184. {
  185. md: 24,
  186. name: 'slot-component',
  187. attributes: { placeholder: '请输入' },
  188. formItemAttributes: {
  189. label: '活动详情图',
  190. prop: 'detailImgs',
  191. rules: [{ required: true, message: '请上传', trigger: 'blur' }]
  192. },
  193. render: (h, { props, onInput }) => {
  194. var { value } = props
  195. return (
  196. <ImageUpload isEdit={!this.formData.id} fileList={this.formData.detailImgs} uid={`questionFiles_detaidetailImgsdetailImgs`} limit={100} isUpdate={false} />
  197. )
  198. }
  199. },
  200. {
  201. md: 24,
  202. name: 'slot-component',
  203. attributes: { placeholder: '请输入' },
  204. formItemAttributes: {
  205. label: '活动说明',
  206. prop: 'content',
  207. rules: []
  208. },
  209. render: (h, { props, onInput }) => {
  210. var { value } = props
  211. return (
  212. <quillEditor disabled={!!this.formData.id} value={value} onInput={onInput}></quillEditor>
  213. )
  214. }
  215. },
  216. {
  217. name: 'slot-component',
  218. md: 24,
  219. formItemAttributes: {
  220. label: '提交记录',
  221. prop: 'promotionQuestionnaireUsers',
  222. rules: [{ required: true, message: '请设置', trigger: 'blur' }]
  223. },
  224. render: (h, { props, onInput }) => {
  225. var { value } = props
  226. return this.convertTableJson(value, [
  227. {
  228. columnAttributes: {
  229. label: '*姓名',
  230. prop: 'name',
  231. },
  232. editRender: (h, { row, column, index }) => {
  233. return (
  234. <div class="redbordererr">
  235. <el-form-item label="" label-width="0px" prop={`promotionQuestionnaireUsers.${index}.${column.columnAttributes.prop}`} rules={[{ required: true, message: '请填写', trigger: 'blur' }]}>
  236. <el-input value={row[column.columnAttributes.prop]} onInput={val => { row[column.columnAttributes.prop] = val }} placeholder="请输入内容"></el-input>
  237. </el-form-item>
  238. </div>
  239. )
  240. },
  241. viewRender: (h, { row, column, index }) => {
  242. return <div style="padding-left:10px">{row[column.columnAttributes.prop]}</div>
  243. }
  244. },
  245. {
  246. columnAttributes: {
  247. label: '*电话',
  248. prop: 'mobile',
  249. },
  250. editRender: (h, { row, column, index }) => {
  251. return (
  252. <div class="redbordererr">
  253. <el-form-item label="" label-width="0px" prop={`promotionQuestionnaireUsers.${index}.${column.columnAttributes.prop}`} rules={mobileRequired}>
  254. <el-input value={row[column.columnAttributes.prop]} onInput={val => { row[column.columnAttributes.prop] = val }} placeholder="请输入内容"></el-input>
  255. </el-form-item>
  256. </div>
  257. )
  258. },
  259. viewRender: (h, { row, column, index }) => {
  260. return <div style="padding-left:10px">{row[column.columnAttributes.prop]}</div>
  261. }
  262. },
  263. {
  264. columnAttributes: {
  265. label: '*时间(分钟)',
  266. prop: 'min',
  267. },
  268. editRender: (h, { row, column, index }) => {
  269. return (
  270. <div class="redbordererr">
  271. <el-form-item label="" label-width="0px" prop={`promotionQuestionnaireUsers.${index}.${column.columnAttributes.prop}`} rules={[{ required: true, message: '请填写', trigger: 'blur' }]}>
  272. <el-input type="number" value={row[column.columnAttributes.prop]} onInput={val => { row[column.columnAttributes.prop] = val }} placeholder="请输入内容"></el-input>
  273. </el-form-item>
  274. </div>
  275. )
  276. },
  277. viewRender: (h, { row, column, index }) => {
  278. return <div style="padding-left:10px">{row[column.columnAttributes.prop]}</div>
  279. }
  280. },
  281. {
  282. columnAttributes: {
  283. label: '*备注',
  284. prop: 'remark',
  285. },
  286. editRender: (h, { row, column, index }) => {
  287. return (
  288. <div class="redbordererr">
  289. <el-form-item label="" label-width="0px" prop={`promotionQuestionnaireUsers.${index}.${column.columnAttributes.prop}`} rules={[{ required: true, message: '请填写', trigger: 'blur' }]}>
  290. <el-input value={row[column.columnAttributes.prop]} onInput={val => { row[column.columnAttributes.prop] = val }} placeholder="请输入内容"></el-input>
  291. </el-form-item>
  292. </div>
  293. )
  294. },
  295. viewRender: (h, { row, column, index }) => {
  296. return <div style="padding-left:10px">{row[column.columnAttributes.prop]}</div>
  297. }
  298. },
  299. ], {
  300. isEdit: !this.formData.id,
  301. isAdd: !this.formData.id,
  302. isDel: !this.formData.id,
  303. }, {
  304. add: ()=>{
  305. this.formData.promotionQuestionnaireUsers.push({
  306. "min": '',
  307. "mobile": "",
  308. "name": "",
  309. "promotionQuestionnaireId": "",
  310. "remark": ""
  311. })
  312. this.isEditTableIndex = this.formData.promotionQuestionnaireUsers.length - 1
  313. },
  314. delete: ({ row, column, index }, cb) => {
  315. if (this.isEditTableIndex == index) {
  316. this.isEditTableIndex = -1
  317. } else if (this.isEditTableIndex > index) {
  318. this.isEditTableIndex--
  319. }
  320. cb && cb()
  321. },
  322. verify: ({ row, column, index }, isEditTableIndex) => {
  323. return new Promise(r => {
  324. if (isEditTableIndex > -1) {
  325. this.$refs.formRef.validateField([
  326. `promotionQuestionnaireUsers.${isEditTableIndex}.min`,
  327. `promotionQuestionnaireUsers.${isEditTableIndex}.mobile`,
  328. `promotionQuestionnaireUsers.${isEditTableIndex}.name`,
  329. `promotionQuestionnaireUsers.${isEditTableIndex}.remark`,
  330. ], (v) => {
  331. if (v) {
  332. r(true)
  333. } else {
  334. r(false)
  335. }
  336. })
  337. } else {
  338. r(true)
  339. }
  340. })
  341. },
  342. })
  343. }
  344. },
  345. ]
  346. },
  347. formItems2(){
  348. return [{
  349. md: 24,
  350. name: 'slot-component',
  351. attributes: { placeholder: '请输入' },
  352. formItemAttributes: {
  353. label: '',
  354. 'label-width': '0px',
  355. prop: 'promotionQuestionnaireItems',
  356. rules: [{ required: true, message: '请设置', trigger: 'blur' }]
  357. },
  358. render: (h, { props, onInput }) => {
  359. return (
  360. <div>
  361. <div>
  362. {!this.formData.id?<el-button type="primary" onClick={()=>{ this.showQuestion = true }}>新增</el-button>:null}
  363. </div>
  364. <div>
  365. <zj-table
  366. columns={[{
  367. columnAttributes: {
  368. label: '填写内容',
  369. prop: '',
  370. },
  371. render: (h, { row, column, index }) => {
  372. return (
  373. <div style="padding:6px;">
  374. <div style="font-weight:bold;">{row.isRequire?<span style="color:red">*</span> : null}{index+1}、{row.question}({['单选','多选','填写','图片','视频'][row.type-1]})</div>
  375. {[
  376. <div>
  377. {row.answer.map(item=><el-radio disabled label="">{item.option_value}</el-radio>)}
  378. </div>,
  379. <div>
  380. {row.answer.map(item=><el-checkbox disabled label="">{item.option_value}</el-checkbox>)}
  381. </div>,
  382. <div>
  383. <el-input disabled placeholder="请输入内容"></el-input>
  384. </div>,
  385. null
  386. ][row.type-1]}
  387. </div>
  388. )
  389. },
  390. },
  391. ...(()=>{
  392. if(!this.formData.id){
  393. return[{
  394. columnAttributes: {
  395. label: '操作',
  396. prop: '',
  397. width: '200px'
  398. },
  399. render: (h, { row, column, index }) => {
  400. return (
  401. <div style="padding-left:5px">
  402. <el-button size="mini" onClick={()=>{
  403. this.questionData = {
  404. ...JSON.parse(JSON.stringify(row)),
  405. rowIndex: index
  406. }
  407. this.$nextTick(()=>{
  408. this.showQuestion = true
  409. })
  410. }}>编辑</el-button>
  411. <el-button size="mini" onClick={()=>{
  412. this.formData.promotionQuestionnaireItems.push({...JSON.parse(JSON.stringify(row))})
  413. }}>复制</el-button>
  414. <el-button size="mini" onClick={()=>{
  415. this.formData.promotionQuestionnaireItems.splice(index, 1)
  416. }}>删除</el-button>
  417. </div>
  418. )
  419. },
  420. }]
  421. }
  422. return []
  423. })()]}
  424. table-data={this.formData.promotionQuestionnaireItems}
  425. />
  426. </div>
  427. </div>
  428. )
  429. }
  430. }]
  431. }
  432. },
  433. methods: {
  434. // 列表请求函数
  435. getList:promotionQuestionnaireList,
  436. // 列表导出函数
  437. exportList: promotionQuestionnaireExport,
  438. // 表格列解析渲染数据更改
  439. columnParsing(item, defaultData) {
  440. if (item.jname === 'qrcode') {
  441. defaultData.render = (h, { row, index, column }) => {
  442. return (
  443. <div style="padding:0 6px;cursor: pointer;">
  444. {row.qrcode ? row.qrcode.split(",").map(url => <el-image src={url} preview-src-list={[url]} fit="fit" style="width:80px;height:80px;" />) : null}
  445. </div>
  446. )
  447. }
  448. }
  449. if (item.jname == 'startTime') {
  450. defaultData.render = (h, { row, index, column }) => {
  451. return (
  452. <div style="padding:0 6px;cursor: pointer;">
  453. {row.startTime && row.startTime.split(" ")[0]}
  454. </div>
  455. )
  456. }
  457. }
  458. if (item.jname == 'endTime') {
  459. defaultData.render = (h, { row, index, column }) => {
  460. return (
  461. <div style="padding:0 6px;cursor: pointer;">
  462. {row.endTime && row.endTime.split(" ")[0]}
  463. </div>
  464. )
  465. }
  466. }
  467. return defaultData
  468. },
  469. // 操作按钮
  470. operation() {
  471. return this.operationBtn({
  472. detail: {
  473. click: ({ row, index, column }) => {
  474. promotionQuestionnaireDetail({
  475. id: row.id
  476. }).then(res=>{
  477. this.formData = {
  478. ...res.data,
  479. submitLimitBool: res.data.submitLimit == -1 ? 0 : 1,
  480. promotionQuestionnaireItems:res.data.promotionQuestionnaireItems.map(item=>{
  481. return {
  482. ...item,
  483. answer: JSON.parse(item?.answer||"[]")
  484. }
  485. }),
  486. banner:res.data?.banner?.split(",").map(url=>({url})),
  487. detailImgs:res.data?.detailImgs?.split(",").map(url=>({url}))
  488. }
  489. this.$nextTick(()=>{
  490. this.formDialog = true
  491. })
  492. })
  493. }
  494. },
  495. createActivity: {
  496. click: ({ row, index, column }) => {
  497. this.$router.push({
  498. name: "activityOrder",
  499. params: {
  500. pageName: row.id,
  501. pageType: 'detail',
  502. pageCode: row.id,
  503. },
  504. })
  505. }
  506. },
  507. viewActivity: {
  508. click: ({ row, index, column }) => {
  509. this.$router.push({
  510. name: "activityOrder",
  511. params: {
  512. pageName: row.id,
  513. pageType: 'list',
  514. pageCode: row.id,
  515. },
  516. })
  517. }
  518. },
  519. })
  520. },
  521. // 新增
  522. addData(){
  523. this.formDialog = true
  524. },
  525. // 关闭弹窗
  526. formCancel(){
  527. this.formDialog = false
  528. this.$data.formData = this.$options.data().formData
  529. },
  530. // 确定
  531. formConfirm() {
  532. this.$refs.formRef.validate((valid, invalidFields, errLabels) => {
  533. if (valid) {
  534. var data = {
  535. ...this.formData,
  536. endTime: this.formData.endTime ? `${this.formData.endTime.split(" ")[0]} 23:59:59` : '',
  537. banner:this.formData.banner.map(item=>item.url).join(","),
  538. detailImgs:this.formData.detailImgs.map(item=>item.url).join(","),
  539. promotionQuestionnaireItems:this.formData.promotionQuestionnaireItems.map(item=>{
  540. return {
  541. ...item,
  542. answer: JSON.stringify(item.answer)
  543. }
  544. }),
  545. submitLimit: !!this.formData.submitLimitBool ? this.formData.submitLimit : -1
  546. }
  547. promotionQuestionnaireAdd(data).then(res=>{
  548. this.$message({
  549. type: 'success',
  550. message: `添加成功!`,
  551. })
  552. this.$refs.pageRef.refreshList()
  553. this.formCancel()
  554. })
  555. }
  556. })
  557. },
  558. // 终止
  559. zhongzhi(){
  560. promotionQuestionnaireStop({
  561. id:this.formData.id
  562. }).then(res=>{
  563. this.$message({
  564. type: 'success',
  565. message: `终止成功!`,
  566. })
  567. this.$refs.pageRef.refreshList()
  568. this.formCancel()
  569. })
  570. },
  571. // 关闭题目编辑
  572. questionClose(){
  573. this.showQuestion = false
  574. this.questionData = {
  575. rowIndex: -1
  576. }
  577. },
  578. // 确定题目编辑
  579. questionConfirm(data){
  580. if(data.rowIndex==-1){
  581. this.formData.promotionQuestionnaireItems.push({...data})
  582. }else{
  583. this.formData.promotionQuestionnaireItems.splice(data.rowIndex, 1, {...data})
  584. }
  585. this.questionClose()
  586. this.$nextTick(()=>{
  587. this.$refs.formRef.validateField(["promotionQuestionnaireItems"], (v) => {})
  588. })
  589. }
  590. }
  591. }
  592. </script>
  593. <style lang="scss">
  594. </style>