EditModal.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. <template>
  2. <div>
  3. <el-dialog :visible.sync="visible" v-bind="modalOptions">
  4. <div>
  5. <el-form ref="formData" :model="formData" :rules="formRules" size="mini" label-suffix=":" label-width="160px">
  6. <div>
  7. <el-tabs v-model="activeName">
  8. <el-tab-pane label="授权信息" name="first">
  9. <el-form-item label="店铺名称" prop="shopName">
  10. <el-input v-model="formData.shopName" maxlength="20" />
  11. </el-form-item>
  12. <el-form-item label="支持的支付类型" prop="payType">
  13. <el-radio-group v-model="formData.payType">
  14. <el-radio :label="9">惠市宝</el-radio>
  15. <el-radio :label="4">通联</el-radio>
  16. <el-radio :label="0">无</el-radio>
  17. </el-radio-group>
  18. </el-form-item>
  19. <el-form-item label="是否支持代金券" prop="isVoucher">
  20. <el-radio-group v-model="formData.isVoucher">
  21. <el-radio :label="1">
  22. 允许
  23. </el-radio>
  24. <el-radio :label="2">
  25. 拒绝
  26. </el-radio>
  27. </el-radio-group>
  28. </el-form-item>
  29. <el-form-item
  30. v-if="formData.isVoucher === 1" :rules="[
  31. { required: true, message: '请输入代金券返还比例', trigger: 'blur' },
  32. { type: 'number', max: 100, min: 0, message: '请输入正确的代金券返还比例,0 ~ 100', trigger: ['blur', 'change'] }
  33. ]" label="代金券返还比例" prop="voucherReturn"
  34. >
  35. <el-input v-model.number="formData.voucherReturn" style="width: 200px;" placeholder="请填写代金券返还比例,范围0 ~ 100">
  36. <template #append>%</template>
  37. </el-input>
  38. </el-form-item>
  39. <el-form-item label="代金券提现比例" prop="voucherCoinRatio">
  40. <el-input-number v-model="formData.voucherCoinRatio" :precision="2" :step="0.01" :max="1"></el-input-number>
  41. <span style="margin-left: 10px;">比例*100</span>
  42. </el-form-item>
  43. <el-form-item label="是否支持消费金" prop="isBeeCoin">
  44. <el-radio-group v-model="formData.isBeeCoin">
  45. <el-radio :label="1">支持</el-radio>
  46. <el-radio :label="2">不支持</el-radio>
  47. </el-radio-group>
  48. </el-form-item>
  49. <el-form-item v-if="formData.isBeeCoin === 1" label="商家消费金提现比例" prop="beeCoinRatio">
  50. <el-input-number v-model="formData.beeCoinRatio" :precision="2" :step="0.01" :max="1"></el-input-number>
  51. <span style="margin-left: 10px;">比例*100</span>
  52. </el-form-item>
  53. <el-form-item label="店铺负责人" prop="chargePersonName">
  54. <el-input v-model="formData.chargePersonName" maxlength="20" />
  55. </el-form-item>
  56. <el-form-item label="负责人电话" prop="chargePersonPhone">
  57. <!-- .replace(/(\d{3})\d+(\d{4})$/, '$1****$2') -->
  58. <el-input v-model="formData.chargePersonPhone" maxlength="11" clearable />
  59. </el-form-item>
  60. <el-form-item label="请选择区域" prop="areaId">
  61. <el-cascader
  62. v-model="regionArrDialog" :props="regionProps" size="large" placeholder="请选择区域"
  63. @change="formData.areaId = regionArrDialog[regionArrDialog.length - 1]"
  64. ></el-cascader>
  65. <div v-if="formData.areaId">已选ID:{{ formData.areaId }}</div>
  66. </el-form-item>
  67. <el-form-item label="官方分类" prop="classifyId">
  68. <el-cascader
  69. v-model="formData.classificationArr" placeholder="请选择官方分类" :options="categoryList"
  70. :props="{ checkStrictly: false, expandTrigger: 'hover', label: 'storeName', value: 'id', children: 'childs' }"
  71. clearable
  72. />
  73. </el-form-item>
  74. <el-form-item label="店铺地址" prop="shopAdress">
  75. <el-input v-model="formData.shopAdress" maxlength="60" />
  76. </el-form-item>
  77. <el-form-item label="店铺经纬度" prop="longitude">
  78. <div>
  79. <span v-if="formData.longitude">
  80. {{ formData.longitude }} - {{ formData.latitude }}
  81. </span>
  82. <el-button
  83. size="mini" type="primary" style="margin-left: 20px;"
  84. @click="$refs.selectAddressMapRef && $refs.selectAddressMapRef.show()"
  85. >
  86. {{ formData.longitude ? '修改' : '选择' }}
  87. </el-button>
  88. </div>
  89. </el-form-item>
  90. <el-form-item label="生效日期" prop="effectiveDate">
  91. <el-date-picker
  92. v-model="formData.effectiveDate" value-format="yyyy-MM-dd" type="date"
  93. placeholder="选择日期"
  94. />
  95. </el-form-item>
  96. <el-form-item label="生效年限" prop="effectiveYear">
  97. <el-input
  98. v-model="formData.effectiveYear" type="text" placeholder="请输入内容" maxlength="4"
  99. class="elipt"
  100. style="width: 50%" show-word-limit
  101. />
  102. <span class="elspan">年</span>
  103. </el-form-item>
  104. <el-form-item label="合同状态" prop="contractState">
  105. <el-radio-group v-model="formData.contractState">
  106. <el-radio :label="1">
  107. 有效
  108. </el-radio>
  109. <el-radio :label="0">
  110. 无效
  111. </el-radio>
  112. </el-radio-group>
  113. </el-form-item>
  114. <el-form-item label="店铺类型" prop="shopType">
  115. <el-radio-group v-model="formData.shopType">
  116. <!-- <el-radio :label="1">品牌厂家</el-radio> -->
  117. <el-radio :label="2">本地</el-radio>
  118. </el-radio-group>
  119. </el-form-item>
  120. <el-form-item
  121. v-if="formData.shopType === 2" prop="startTime" label="营业开始时间" :rules="[
  122. { required: true, message: '请选择营业开始时间', trigger: 'blur' }
  123. ]"
  124. >
  125. <el-time-select
  126. v-model="formData.startTime" placeholder="起始时间"
  127. :picker-options="{ start: '00:00', step: '00:05' }"
  128. >
  129. </el-time-select>
  130. </el-form-item>
  131. <el-form-item
  132. v-if="formData.shopType === 2" prop="endTime" label="营业结束时间" :rules="[
  133. { required: true, message: '请选择营业结束时间', trigger: 'blur' }
  134. ]"
  135. >
  136. <el-time-select
  137. v-model="formData.endTime" placeholder="营业结束时间"
  138. :picker-options="{ start: '00:00', step: '00:05', end: '24:00' }"
  139. >
  140. </el-time-select>
  141. </el-form-item>
  142. <el-form-item label="惠市宝商家编号">
  143. <el-input v-model="formData.hsbMrchId" maxlength="60" />
  144. </el-form-item>
  145. <el-form-item label="直播间审核" prop="auditLive">
  146. <el-radio-group v-model="formData.auditLive">
  147. <el-radio :label="1">开启</el-radio>
  148. <el-radio :label="0">关闭</el-radio>
  149. </el-radio-group>
  150. </el-form-item>
  151. <el-form-item label="直播间商品审核" prop="auditLiveProduct">
  152. <el-radio-group v-model="formData.auditLiveProduct">
  153. <el-radio :label="1">
  154. 开启
  155. </el-radio>
  156. <el-radio :label="0">
  157. 关闭
  158. </el-radio>
  159. </el-radio-group>
  160. </el-form-item>
  161. <el-form-item label="兑换商品是否需要核销" prop="exchangeIsNeedVerification">
  162. <el-radio-group v-model="formData.exchangeIsNeedVerification">
  163. <el-radio :label="1">
  164. </el-radio>
  165. <el-radio :label="0">
  166. </el-radio>
  167. </el-radio-group>
  168. </el-form-item>
  169. <el-form-item class="b-shop-rate" prop="score" label="评分">
  170. <el-rate v-model="formData.score"></el-rate>
  171. </el-form-item>
  172. <el-form-item prop="monthlySales" label="月售">
  173. <el-input v-model.number="formData.monthlySales" placeholder="请输入商家月售额" type="number"></el-input>
  174. </el-form-item>
  175. <el-form-item prop="perCapita" label="人均">
  176. <el-input v-model.number="formData.perCapita" type="number" placeholder="请输入人均消费额" closeable></el-input>
  177. </el-form-item>
  178. <el-form-item prop="shopBrief" label="商家简介">
  179. <el-input
  180. v-model="formData.shopBrief" autosize maxlength="250" show-word-limit
  181. type="textarea"
  182. placeholder="请输入商家简介" closeable
  183. ></el-input>
  184. </el-form-item>
  185. <el-form-item prop="advertisement" label="广告图">
  186. <!-- <el-upload
  187. class="avatar-uploader" list-type="picture-card" :file-list="formData.advertisement"
  188. :action="uploadUrl"
  189. :on-success="(r) => formData.advertisement.push({ url: r.url, uid: r.url + Math.random() + Date.now() })"
  190. :on-remove="(e) => formData.advertisement.filter((item) => item.uid !== e.uid)"
  191. >
  192. <i class="el-icon-plus avatar-uploader-icon" />
  193. </el-upload> -->
  194. <el-upload
  195. class="avatar-uploader" list-type="picture-card" :file-list="uploadList"
  196. :action="uploadUrl"
  197. :on-success="uploadSuccess"
  198. :on-remove="removeSuccess"
  199. >
  200. <i class="el-icon-plus avatar-uploader-icon" />
  201. </el-upload>
  202. </el-form-item>
  203. </el-tab-pane>
  204. <el-tab-pane label="客户信息" name="second">
  205. <el-form-item label="账号" prop="shopPhone" maxlength="20">
  206. <el-input ref="shopPhoneCls" v-model="formData.shopPhone" maxlength="20" />
  207. </el-form-item>
  208. <el-form-item label="密码" prop="shopPassword">
  209. <el-input v-model="formData.shopPassword" type="password" maxlength="16" />
  210. </el-form-item>
  211. </el-tab-pane>
  212. </el-tabs>
  213. </div>
  214. </el-form>
  215. </div>
  216. <template #footer>
  217. <span class="dialog-footer">
  218. <el-button size="mini" @click="handleClose">取 消</el-button>
  219. <el-button v-if="activeName === 'first'" type="primary" size="mini" @click="activeName = 'second'">
  220. 下一步
  221. </el-button>
  222. <el-button v-else-if="activeName === 'second'" type="primary" size="mini" @click="handleSubmit">确 定</el-button>
  223. </span>
  224. </template>
  225. </el-dialog>
  226. <!-- 选择经纬度 -->
  227. <SelectAddressMap
  228. ref="selectAddressMapRef"
  229. @select="(address) => (formData.longitude = address[0]) && (formData.latitude = address[1])"
  230. ></SelectAddressMap>
  231. </div>
  232. </template>
  233. <script>
  234. import SelectAddressMap from './SelectAddressMap'
  235. import { businessListGetById, businessListUpdate, businessListSave, businessClassList } from '@/api/business'
  236. import { getProvinceList, getChildAreaList } from '@/api/address'
  237. import { uploadUrl } from '@/utils/request'
  238. import XeUtils from 'xe-utils'
  239. export default {
  240. name: 'EditModal',
  241. components: {
  242. SelectAddressMap
  243. },
  244. data() {
  245. return {
  246. modalOptions: {
  247. closeOnClickModal: false,
  248. width: '820px',
  249. title: ''
  250. },
  251. visible: false,
  252. formData: {
  253. shopId: '',
  254. shopName: '', // 店铺名称
  255. voucherCoinRatio: '', // 代金券提现比例
  256. isBeeCoin: '', // 是否支持消费金
  257. beeCoinRatio: '', // 商家消费金提现比例
  258. chargePersonName: '', // 店铺负责人
  259. chargePersonPhone: '', // 负责人电话
  260. shopAdress: '', // 地址
  261. effectiveDate: '', // 生效日期
  262. effectiveYear: '', // 生效年限
  263. shopType: 2, // 商家类型 1 商家 2 本地
  264. payType: 0, // 支付类型
  265. isVoucher: 1, // 是否支持代金卷 1 true 2 false
  266. voucherReturn: '',
  267. contractState: 1, // 合同状态 1-有效 0-无效
  268. auditLive: 1,
  269. auditLiveProduct: 1,
  270. exchangeIsNeedVerification: 0,
  271. shopPhone: '', // 账号
  272. shopPassword: '', // 密码
  273. perCapita: '', // 人均
  274. score: '', // 评分
  275. advertisement: [], // 广告图
  276. areaId: '', // 区域id
  277. hsbMrchId: '', // 惠市宝商家编号,不是必填
  278. longitude: '', // 经纬度
  279. latitude: '', // 经纬度
  280. classificationId: '', // 商家分类id
  281. classificationArr: [], // 非后端参数
  282. startTime: '',
  283. endTime: '',
  284. shopBrief: '', // 商家简介
  285. monthlySales: ''
  286. },
  287. formRules: {
  288. shopName: [ { required: true, message: '请输入店铺名称' } ],
  289. effectiveDate: [ { required: true, message: '请输入生效日期' } ],
  290. effectiveYear: [ { required: true, message: '请输入生效年限' } ],
  291. chargePersonName: [ { required: true, message: '请输入店铺负责人', trigger: 'blur' } ],
  292. chargePersonPhone: [
  293. { required: true, message: '请输入负责人电话', trigger: 'blur' },
  294. { pattern: /^1[3456789]\d{9}$/, message: '目前只支持中国大陆的手机号码' }
  295. ],
  296. shopAdress: [ { required: true, message: '请输入地址', trigger: 'blur' } ],
  297. contractState: [ { required: true, message: '请选择合同状态', trigger: 'change' } ],
  298. shopType: [ { required: true, message: '请选择店铺类型', trigger: 'change' } ],
  299. perCapita: [ { required: true, message: '请输入人均消费额', trigger: 'blur' } ],
  300. shopBrief: [ { required: true, message: '请填写商家介绍', trigger: 'blur' } ],
  301. isVoucher: [ { required: true, message: '请选择是否允许使用代金卷', trigger: 'change' } ],
  302. auditLive: [ { required: true, message: '请选择状态', trigger: 'change' } ],
  303. auditLiveProduct: [ { required: true, message: '请选择状态', trigger: 'change' } ],
  304. exchangeIsNeedVerification: [ { required: true, message: '请选择状态', trigger: 'change' } ],
  305. score: [ { required: true, message: '请选择商家评分', trigger: 'change' } ],
  306. monthlySales: [ { required: true, message: '请输入商家月售额', trigger: 'blur' } ],
  307. // advertisement: [ { required: true, message: '请上传广告图', trigger: 'trigger' } ],
  308. // classificationArr: [ { required: true, type: 'array', message: '请选择分类' } ],
  309. areaId: [ { required: true, message: '请选择地址', trigger: 'blur' } ],
  310. longitude: [ { required: true, message: '请选择商家经纬度', trigger: 'blur' } ],
  311. isBeeCoin: [ { required: true, message: '请选择是否支持消费金' } ],
  312. beeCoinRatio: [],
  313. shopPhone: [
  314. { required: true, message: '请输入账号', trigger: 'blur' },
  315. { pattern: /^1[3456789]\d{9}$/, message: '目前只支持中国大陆的手机号码' }
  316. ],
  317. shopPassword: [
  318. { required: true, message: '请输入密码', trigger: 'blur' },
  319. { pattern: /^[~!@#$%^&*\-+=_.0-9a-zA-Z]{8,16}$/, message: '8-16密码数字英文混合' }
  320. ]
  321. },
  322. activeName: 'first',
  323. regionArrDialog: [],
  324. regionProps: {
  325. lazy: true,
  326. label: 'name',
  327. value: 'id',
  328. lazyLoad(node, resolve) {
  329. const { level, value } = node
  330. if (level === 0) {
  331. getProvinceList().then((res) => {
  332. resolve(res.data)
  333. })
  334. } else if (level != 0) {
  335. getChildAreaList(value).then((res) => {
  336. resolve(res.data.map((item) => {
  337. item.leaf = level === 3
  338. return item
  339. }))
  340. })
  341. }
  342. }
  343. },
  344. uploadUrl,
  345. categoryList: [],
  346. uploadList: []
  347. }
  348. },
  349. watch: {
  350. 'formData.isBeeCoin': {
  351. deep: true,
  352. handler(val) {
  353. if (val === 1) {
  354. this.formRules.beeCoinRatio = [
  355. { required: true, message: '请输入商家消费金提现比例' },
  356. { pattern: /^0\.\d{0,2}$|^[1-9]\d*\.\d{0,2}$|^[1-9]\d*$/, message: '数值有误' }
  357. ]
  358. } else {
  359. this.formRules.beeCoinRatio = []
  360. }
  361. }
  362. }
  363. },
  364. created() {
  365. this.getCategoryTreeList()
  366. },
  367. methods: {
  368. handleClose() {
  369. this.visible = false
  370. },
  371. async getCategoryTreeList() {
  372. const res = await businessClassList({ page: 1, pageSize: 9999 })
  373. XeUtils.eachTree(res.data.records, (item) => {
  374. if (Array.isArray(item.childs) && item.childs.length === 0) {
  375. item.childs = undefined
  376. }
  377. }, { children: 'childs' })
  378. this.categoryList = res.data.records
  379. },
  380. initList() {
  381. },
  382. handleOpen(params = {}) {
  383. this.modalOptions.title = params.shopId ? '修改商家' : '新增商家'
  384. this.formData = Object.assign(this.$options.data().formData, params, {
  385. // advertisement: params.advertisement ? params.advertisement.split(',').map((item) => ({ url: item, uid: item + Math.random() + new Date() })) : []
  386. })
  387. // this.uploadList = this.formData.advertisement.split("&")
  388. const categoryItem = XeUtils.findTree(this.categoryList, (item) => item.id === String(params.classificationId))
  389. if (categoryItem && Array.isArray(categoryItem.nodes)) {
  390. this.formData.classificationArr = categoryItem.nodes.map((v) => v.id)
  391. }
  392. if (this.formData.areaId) this.regionArrDialog = [ this.formData.areaId ]
  393. this.visible = true
  394. this.initList()
  395. if (params.shopId) {
  396. this.getInfo(params.shopId)
  397. } else {
  398. this.$refs.formData && this.$refs.formData.resetFields()
  399. }
  400. },
  401. async getInfo(id) {
  402. const loading = this.$loading({ text: '加载中' })
  403. try {
  404. const res = await businessListGetById({ shopId: id })
  405. this.formData = Object.assign(this.$options.data().formData, res.data, {
  406. shopId: res.data.shopId || '',
  407. voucherReturn: Number(res.data.voucherReturn)
  408. // advertisement: res.data.advertisement ? res.data.advertisement.split(',').map((item) => ({ url: item, uid: item + Math.random() + new Date() })) : []
  409. // advertisement
  410. })
  411. const arr = this.formData.advertisement.split(',')
  412. if (arr[0] == '') {
  413. this.uploadList = []
  414. } else {
  415. this.uploadList = arr.map((item) => ({
  416. url: item,
  417. uid: item + Math.random() + new Date()
  418. }))
  419. }
  420. const categoryItem = XeUtils.findTree(this.categoryList, (item) => item.id === String(res.data.classificationId))
  421. if (categoryItem && Array.isArray(categoryItem.nodes)) {
  422. this.formData.classificationArr = categoryItem.nodes.map((v) => v.id)
  423. }
  424. if (this.formData.areaId) this.regionArrDialog = [ this.formData.areaId ]
  425. this.$nextTick(() => {
  426. this.$refs.formData && this.$refs.formData.validate()
  427. })
  428. } finally {
  429. loading.close()
  430. }
  431. },
  432. handleSubmit() {
  433. this.$refs.formData.validate(async (valid) => {
  434. if (valid) {
  435. const loading = this.$loading({ text: '加载中' })
  436. try {
  437. const { advertisement, classificationArr, ...otps } = this.formData
  438. const params = {
  439. ...otps,
  440. // advertisement: Array.isArray(advertisement) ? advertisement.map((v) => v.url || v).join(',') : '',
  441. classificationId: Array.isArray(classificationArr) && classificationArr.length ? classificationArr[classificationArr.length - 1] : ''
  442. }
  443. params.advertisement = this.uploadList.reduce((prev, item, index) => {
  444. prev += item.url + ','
  445. return prev
  446. }, '')
  447. // 删除最后一个字符
  448. params.advertisement = params.advertisement.substring(0, params.advertisement.length - 1)
  449. this.formData.shopId ? await businessListUpdate(params) : await businessListSave(params)
  450. loading.close()
  451. this.$message({ message: `${this.formData.shopId ? '编辑' : '添加'}成功!`, type: 'success' })
  452. this.$emit('success')
  453. this.visible = false
  454. } catch (e) {
  455. loading.close()
  456. } finally {
  457. loading.close()
  458. }
  459. } else {
  460. this.$message({ message: '请输入相关信息', type: 'warning' })
  461. return false
  462. }
  463. })
  464. },
  465. uploadSuccess(r) {
  466. console.log(r)
  467. this.uploadList.push({ url: r.data.url, uid: r.url + Math.random() + Date.now() })
  468. },
  469. removeSuccess(r) {
  470. this.uploadList = this.uploadList.filter((item) => item.uid !== r.uid)
  471. }
  472. }
  473. }
  474. </script>