configurate.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626
  1. <template>
  2. <div class="configurate">
  3. <div class="steps">
  4. <el-steps style="width: 800px" :active="active" finish-status="success" simple>
  5. <el-step title="配置基本信息" />
  6. <el-step title="配置奖品" />
  7. <el-step title="配置完成" />
  8. </el-steps>
  9. </div>
  10. <div class="content" v-if="active===0">
  11. <el-row :gutter="20" style="height: 100%">
  12. <el-col :span="4" class="image">
  13. <img v-if="basicForm.actMethod=='2'" src="@/assets/images/zhuanpan.png" />
  14. <img v-else src="@/assets/images/jiugongge.png" />
  15. </el-col>
  16. <el-col :span="20">
  17. <el-descriptions title="基本信息">
  18. <el-descriptions-item>
  19. <el-form ref="BasicFormRef" :model="basicForm" :rules="basicRules">
  20. <el-row :gutter="20">
  21. <el-col :span="12">
  22. <el-form-item label="活动名称" prop="actName">
  23. <el-input v-model="basicForm.actName" placeholder="输入活动名称"></el-input>
  24. </el-form-item>
  25. </el-col>
  26. <el-col :span="12">
  27. <el-form-item label="抽奖方式" prop="actMethod">
  28. <el-radio-group v-model="basicForm.actMethod">
  29. <el-radio-button label="大转盘" value="2"></el-radio-button>
  30. <el-radio-button label="九宫格" value="1"></el-radio-button>
  31. </el-radio-group>
  32. </el-form-item>
  33. </el-col>
  34. </el-row>
  35. <el-row :gutter="20">
  36. <el-col :span="12">
  37. <el-form-item label="开始时间" prop="actStartTime">
  38. <el-date-picker
  39. v-model="basicForm.actStartTime"
  40. type="date"
  41. placeholder="请选择"
  42. format="YYYY-MM-DD"
  43. value-format="YYYY-MM-DD"
  44. :disabled-date="disabledDateStart"
  45. style="width: 100%"
  46. />
  47. </el-form-item>
  48. </el-col>
  49. <el-col :span="12">
  50. <el-form-item label="结束时间" prop="actEndTime">
  51. <el-date-picker
  52. v-model="basicForm.actEndTime"
  53. type="date"
  54. placeholder="请选择"
  55. format="YYYY-MM-DD"
  56. value-format="YYYY-MM-DD"
  57. :disabled-date="disabledDateEnd"
  58. style="width: 100%"
  59. />
  60. </el-form-item>
  61. </el-col>
  62. </el-row>
  63. <el-row :gutter="20">
  64. <el-col :span="12">
  65. <el-form-item label="所属机构" prop="actDept">
  66. <el-cascader
  67. clearable
  68. v-model="basicForm.actDept"
  69. :options="option"
  70. :props="cascaderProps"
  71. style="width: 100%"
  72. placeholder="选择机构"
  73. filterable
  74. ></el-cascader>
  75. </el-form-item>
  76. </el-col>
  77. </el-row>
  78. </el-form>
  79. </el-descriptions-item>
  80. </el-descriptions>
  81. <el-divider />
  82. <el-descriptions title="参与限制">
  83. <el-descriptions-item>
  84. <div>
  85. <a>参与机构</a>&nbsp;&nbsp;&nbsp;
  86. <el-button link type="primary" @click="selectDeptData">
  87. 选择
  88. </el-button>
  89. </div>
  90. <el-table
  91. :data="deptData"
  92. height="330"
  93. >
  94. <el-table-column label="机构" prop="name"></el-table-column>
  95. <el-table-column label="操作" width="150">
  96. <template #default="scope">
  97. <el-button link type="primary" @click="deleteDeptData(scope)">
  98. 删除
  99. </el-button>
  100. </template>
  101. </el-table-column>
  102. </el-table>
  103. </el-descriptions-item>
  104. </el-descriptions>
  105. <div class="btns">
  106. <el-button plain @click="cancelFirst(BasicFormRef)">取消</el-button>
  107. <el-button type="primary" @click="confirmFirst(BasicFormRef)">下一步</el-button>
  108. </div>
  109. </el-col>
  110. </el-row>
  111. </div>
  112. <div class="content" v-if="active===1">
  113. <el-row :gutter="20" style="height: 100%">
  114. <el-col :span="4" class="image">
  115. <img v-if="basicForm.actMethod=='2'" src="@/assets/images/zhuanpan.png" />
  116. <img v-else src="@/assets/images/jiugongge.png" />
  117. </el-col>
  118. <el-col :span="20">
  119. <el-descriptions title="奖品配置" style="height: 650px;">
  120. <el-descriptions-item>
  121. <el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
  122. <el-tab-pane v-for="(item, index) in gifts" :label="item.tab.label" :name="item.tab.name" :key="index">
  123. <el-form :model="item.form" label-width="70">
  124. <el-form-item label="奖品分类" prop="type">
  125. <el-radio-group v-model="item.form.awardType">
  126. <el-radio value="1">现金</el-radio>
  127. <el-radio value="2">增值</el-radio>
  128. </el-radio-group>
  129. <div v-if="item.form.awardType=='1'" style="display: flex; align-items: center; margin-left: 20px;">
  130. <span>面值类型:</span>
  131. <el-select v-model="item.form.awardCashType" style="width: 150px;">
  132. <el-option label="固定面值" value="1"></el-option>
  133. <el-option label="区间面值" value="2"></el-option>
  134. </el-select>
  135. </div>
  136. </el-form-item>
  137. <el-form-item label="奖品名称" prop="name">
  138. <el-input v-model="item.form.awardName" placeholder="请输入"></el-input>
  139. </el-form-item>
  140. <el-form-item label="现金面值" prop="money" v-if="item.form.awardType=='1'">
  141. <el-input v-if="item.form.awardCashType == '1'" v-model="item.form.awardFixedAmount" placeholder="请输入"></el-input>
  142. <div v-else style="display: flex; align-items: center">
  143. <el-input v-model="item.form.awardMinAmount" placeholder="请输入"></el-input>
  144. &nbsp;至&nbsp;
  145. <el-input v-model="item.form.awardMaxAmount" placeholder="请输入"></el-input>
  146. </div>
  147. </el-form-item>
  148. <el-form-item label="奖品图" prop="image">
  149. <el-upload v-if="item.form.imageUrl" style="display: inline" :auto-upload="false" :show-file-list="false" accept=".png, .jpg, .jpeg" @change="uploadImage($event, item)">
  150. <img class="imageUrl" :src="item.form.imageUrl" />
  151. </el-upload>
  152. <el-upload v-else style="display: inline" :auto-upload="false" :show-file-list="false" accept=".png, .jpg, .jpeg" @change="uploadImage($event, item)">
  153. <el-icon class="btn-icon"><Plus /></el-icon>
  154. </el-upload>
  155. </el-form-item>
  156. </el-form>
  157. </el-tab-pane>
  158. </el-tabs>
  159. </el-descriptions-item>
  160. </el-descriptions>
  161. <div class="btns">
  162. <el-button plain @click="cancelSecond">取消</el-button>
  163. <el-button type="primary" @click="confirmSecond(BasicFormRef)">下一步</el-button>
  164. </div>
  165. </el-col>
  166. </el-row>
  167. </div>
  168. <div class="content" v-if="active===2 || active===3">
  169. <div class="result">
  170. <el-result
  171. icon="success"
  172. title="奖品配置完成!"
  173. >
  174. <template #extra>
  175. <el-button type="primary" @click="back">返回</el-button>
  176. </template>
  177. </el-result>
  178. </div>
  179. </div>
  180. <el-dialog
  181. v-model="selectDeptShow"
  182. title="参与机构选择"
  183. width="600"
  184. >
  185. <el-input
  186. v-model="filterText"
  187. style="width: 240px"
  188. placeholder="输入名称"
  189. :prefix-icon="Search"
  190. />
  191. <el-tree
  192. ref="treeRef"
  193. class="filter-tree"
  194. show-checkbox
  195. node-key="id"
  196. :data="option"
  197. :props="defaultProps"
  198. :check-strictly="true"
  199. :default-expand-all="true"
  200. :filter-node-method="filterNode"
  201. @check="getCheckedNodes"
  202. />
  203. <template #footer>
  204. <el-button plain @click="cancelCheckDept">取消</el-button>
  205. <el-button type="primary" @click="confirmCheckDept">确认</el-button>
  206. </template>
  207. </el-dialog>
  208. </div>
  209. </template>
  210. <script setup lang="ts">
  211. import { ref } from 'vue'
  212. import type { FormRules, FormInstance, ElTree } from "element-plus";
  213. import { Search } from '@element-plus/icons-vue'
  214. import api from '@/api'
  215. import {ElMessage, ElMessageBox} from "element-plus";
  216. import { useRouter, useRoute } from 'vue-router'
  217. const router = useRouter()
  218. const route = useRoute()
  219. let active = ref(0)
  220. const BasicFormRef = ref<FormInstance>()
  221. let basicForm = ref({
  222. deptIds: [],
  223. actMethod: '2'
  224. })
  225. const basicRules = ref<FormRules>({
  226. actName: [
  227. { required: true, trigger: "blur", message: "请填写活动名称" }
  228. ],
  229. actMethod: [
  230. { required: true, trigger: "change", message: "请选择抽奖方式" }
  231. ],
  232. actStartTime: [
  233. { required: true, trigger: "blur", message: "请选择开始时间" }
  234. ],
  235. actEndTime: [
  236. { required: true, trigger: "blur", message: "请选择结束时间" }
  237. ],
  238. actDept: [
  239. { required: true, trigger: "change", message: "请选择所属机构" }
  240. ]
  241. })
  242. const disabledDateStart = (time: Date) => {
  243. return time.getTime() < Date.now() - 8.64e7
  244. }
  245. const disabledDateEnd = (time: Date) => {
  246. return time.getTime() < new Date(basicForm.value.actStartTime) - 8.64e7
  247. }
  248. let deptData = ref([])
  249. let activeName = ref('1')
  250. let gifts = ref([
  251. {
  252. tab: {
  253. label: '奖品1',
  254. name: '1'
  255. },
  256. form: {
  257. awardType: '1',
  258. awardCashType: '1'
  259. }
  260. },{
  261. tab: {
  262. label: '奖品2',
  263. name: '2'
  264. },
  265. form: {
  266. awardType: '1',
  267. awardCashType: '1'
  268. }
  269. }
  270. ])
  271. const handleClick = (tab, event) => {
  272. }
  273. // 机构
  274. let option = ref([])
  275. const cascaderProps = {
  276. value: 'id',
  277. label: 'name',
  278. children: 'children',
  279. checkStrictly: true,
  280. }
  281. const institutionList = () => {
  282. api.institutionApi.institutionList({ name: '', system: '' }).then(res => {
  283. if(res?.code == 200) {
  284. option.value = res.data
  285. } else {
  286. ElMessage({
  287. message: res.msg,
  288. type: 'warning'
  289. })
  290. }
  291. })
  292. }
  293. // 第一步取消
  294. const cancelFirst = (BasicFormRef: FormInstance) => {
  295. router.push({
  296. path: '/marketingManagement/lottery'
  297. })
  298. }
  299. const confirmFirst = async (BasicFormRef: FormInstance) => {
  300. if(!BasicFormRef) {
  301. BasicFormRef.resetFields()
  302. return
  303. }
  304. await BasicFormRef.validate((valid) => {
  305. if(valid) {
  306. if(basicForm.value.deptIds.length>0) {
  307. api.lotteryApi.checkActivityDept({
  308. deptIds: basicForm.value.deptIds
  309. }).then(res => {
  310. if(res.code == 200) {
  311. if(res.data == '1') {
  312. ElMessageBox({
  313. title: '提示',
  314. message: '选择的参与机构存在有效的抽奖活动,发布后新的抽奖活动将覆盖机构的抽奖活动,请确认是否继续发布',
  315. type: 'warning',
  316. showCancelButton: true,
  317. confirmButtonText: '继续发布',
  318. cancelButtonText: '取消',
  319. }).then(( action ) => {
  320. if(action === 'confirm') {
  321. active.value = 1
  322. } else {
  323. active.value = 0
  324. }
  325. })
  326. } else {
  327. active.value = 1
  328. }
  329. } else {
  330. ElMessage({
  331. message: res.msg,
  332. type: 'warning'
  333. })
  334. }
  335. })
  336. } else {
  337. ElMessage({
  338. message: '请勾选参与机构!',
  339. type: 'warning'
  340. })
  341. }
  342. } else {
  343. ElMessage({
  344. message: '请正确填写相关信息!',
  345. type: 'warning'
  346. })
  347. }
  348. })
  349. }
  350. const uploadImage = async (file, item) => {
  351. let files = file.raw
  352. const params = new FormData(); // 声明formData数据类型
  353. params.append("file", files);
  354. params.append("type", "image");
  355. const { code, data, msg } = await api.commonApi.fileUpload(params)
  356. if(code == 200) {
  357. item.form.awardImg = data.id
  358. item.form.imageUrl = data.downloadUrl
  359. }
  360. }
  361. const cancelSecond = () => {
  362. active.value = 0
  363. }
  364. const confirmSecond = (BasicFormRef: FormInstance) => {
  365. console.log(123123213, basicForm.value)
  366. let awardList = gifts.value.map((item) => {
  367. if(item.form.awardCashType == '1') {
  368. return {
  369. awardId: item.form.id?item.form.id:null,
  370. awardType: item.form.awardType,
  371. awardCashType: item.form.awardCashType,
  372. awardName: item.form.awardName,
  373. awardFixedAmount: item.form.awardFixedAmount,
  374. awardImg: item.form.awardImg,
  375. }
  376. } else {
  377. return {
  378. awardId: item.form.id?item.form.id:null,
  379. awardType: item.form.awardType,
  380. awardCashType: item.form.awardCashType,
  381. awardName: item.form.awardName,
  382. awardMinAmount: item.form.awardMinAmount,
  383. awardMaxAmount: item.form.awardMaxAmount,
  384. awardImg: item.form.awardImg,
  385. }
  386. }
  387. })
  388. let formData = {...basicForm.value}
  389. if(typeof basicForm.value.actDept != 'string') {
  390. formData.actDept = basicForm.value.actDept[basicForm.value.actDept.length-1]
  391. }
  392. formData.awardList = awardList
  393. if(route.query.id) {
  394. api.lotteryApi.updateActivity(formData).then(res => {
  395. if(res.code == 200) {
  396. ElMessage({
  397. message: res.msg,
  398. type: 'success'
  399. })
  400. active.value = 3
  401. } else {
  402. ElMessage({
  403. message: res.msg,
  404. type: 'warning'
  405. })
  406. }
  407. })
  408. } else {
  409. api.lotteryApi.addActivity(formData).then(res => {
  410. if(res.code == 200) {
  411. ElMessage({
  412. message: res.msg,
  413. type: 'success'
  414. })
  415. active.value = 3
  416. } else {
  417. ElMessage({
  418. message: res.msg,
  419. type: 'warning'
  420. })
  421. }
  422. BasicFormRef.resetFields()
  423. })
  424. }
  425. // api.lotteryApi.addActivityAward({
  426. // awardList: awardList,
  427. // activityId: activityId.value
  428. // }).then(res => {
  429. // if(res.code == 200) {
  430. // ElMessage({
  431. // message: res.msg,
  432. // type: 'success'
  433. // })
  434. // active.value = 3
  435. // } else {
  436. // ElMessage({
  437. // message: res.msg,
  438. // type: 'warning'
  439. // })
  440. // }
  441. // })
  442. }
  443. // 回显相关数据
  444. let editData = ref(null)
  445. let checkedDeptIds = ref([])
  446. let checkedDeptData = ref([])
  447. const initEdit = (id) => {
  448. api.lotteryApi.getActivity({ id: id }).then(res => {
  449. if(res.code == 200) {
  450. editData.value = {...res.data}
  451. basicForm.value = {...editData.value}
  452. checkedDeptIds.value = res.data.deptIds
  453. checkedDeptData.value = res.data.deptData
  454. deptData.value = checkedDeptData.value
  455. if(res.data.awardList&&res.data.awardList.length>0) {
  456. gifts.value.forEach((item, index) => {
  457. item.form = res.data.awardList[index]
  458. })
  459. }
  460. } else {
  461. ElMessage({
  462. message: res.msg,
  463. type: 'warning'
  464. })
  465. }
  466. })
  467. }
  468. // 参与机构数选择弹框
  469. let selectDeptShow = ref(false)
  470. let filterText = ref('')
  471. const treeRef = ref<InstanceType<typeof ElTree>>()
  472. const defaultProps = {
  473. children: 'children',
  474. label: 'name',
  475. }
  476. watch(filterText, (val) => {
  477. treeRef.value!.filter(val)
  478. })
  479. const selectDeptData = () => {
  480. selectDeptShow.value = true
  481. nextTick(() => {
  482. treeRef.value!.setCheckedKeys([...basicForm.value.deptIds], true)
  483. })
  484. }
  485. const deleteDeptData = (scope) => {
  486. ElMessageBox({
  487. title: '删除机构',
  488. message: '确定要删除该机构吗?',
  489. type: 'warning',
  490. showCancelButton: true,
  491. confirmButtonText: '确定',
  492. cancelButtonText: '取消',
  493. }).then(( action ) => {
  494. if(action === 'confirm') {
  495. let arr = deptData.value.filter(item => item.id != scope.row.id)
  496. let brr = basicForm.value.deptIds.filter(item => item != scope.row.id)
  497. checkedDeptData.value = [...arr]
  498. checkedDeptIds.value = [...brr]
  499. basicForm.value.deptIds = [...checkedDeptIds.value]
  500. deptData.value = [...checkedDeptData.value]
  501. }
  502. }).catch(( action ) => {
  503. })
  504. }
  505. const filterNode = (value: string, data: any) => {
  506. if (!value) return true
  507. return data.name.includes(value)
  508. }
  509. const getCheckedNodes = (a, b) => {
  510. checkedDeptIds.value = [...b.checkedKeys]
  511. checkedDeptData.value = [...b.checkedNodes]
  512. }
  513. const cancelCheckDept = () => {
  514. selectDeptShow.value = false
  515. checkedDeptIds.value = [...basicForm.value.deptIds]
  516. checkedDeptData.value = [...deptData.value]
  517. // if(route.query.id) {
  518. // selectDeptShow.value = false
  519. // checkedDeptIds.value = [...basicForm.value.deptIds]
  520. // checkedDeptData.value = [...deptData.value]
  521. // } else {
  522. // checkedDeptIds.value = []
  523. // checkedDeptData.value = []
  524. // basicForm.value.deptIds = []
  525. // deptData.value = []
  526. // }
  527. }
  528. const confirmCheckDept = () => {
  529. selectDeptShow.value = false
  530. basicForm.value.deptIds = [...checkedDeptIds.value]
  531. deptData.value = [...checkedDeptData.value]
  532. }
  533. const back = () => {
  534. router.push({
  535. path: '/marketingManagement/lottery'
  536. })
  537. }
  538. onMounted(() => {
  539. institutionList()
  540. if(route.query.id) {
  541. initEdit(route.query.id)
  542. }
  543. })
  544. </script>
  545. <style scoped lang="scss">
  546. .configurate{
  547. width: calc(100% - 40px);
  548. margin: 20px;
  549. background: white;
  550. .steps{
  551. width: 100%;
  552. display: flex;
  553. align-content: center;
  554. justify-content: center;
  555. }
  556. .content{
  557. height: 688px;
  558. .image{
  559. display: flex;
  560. align-items: center;
  561. justify-content: center;
  562. img{
  563. width: calc(100% - 20px);
  564. height: 70%;
  565. }
  566. }
  567. .btns{
  568. display: flex;
  569. align-items: center;
  570. justify-content: center;
  571. }
  572. .imageUrl{
  573. width: 100px;
  574. height: 100px;
  575. border-radius: 5px;
  576. }
  577. .btn-icon{
  578. border: 1px solid #ccc;
  579. width: 100px;
  580. height: 100px;
  581. font-size: 30px;
  582. color: #ccc;
  583. border-radius: 5px;
  584. }
  585. .result{
  586. width: 100%;
  587. height: 100%;
  588. display: flex;
  589. align-items: center;
  590. justify-content: center;
  591. }
  592. }
  593. :deep(.el-steps--simple) {
  594. background: none;
  595. }
  596. :deep(.el-step__head.is-success) {
  597. color: #00a0f4;
  598. border-color: #00a0f4;
  599. }
  600. :deep(.el-step__title.is-success) {
  601. color: #00a0f4;
  602. }
  603. }
  604. </style>