CouponManage.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. <template>
  2. <page-layer>
  3. <template #header>
  4. <el-button type="primary" icon="Refresh" @click="refreshCoupons(true)">刷新数据</el-button>
  5. <el-button type="primary" icon="Plus" plain @click="createNewCoupon">新增优惠券</el-button>
  6. </template>
  7. <template #main>
  8. <el-table :data="coupons" stripe :height="tableHeight">
  9. <el-table-column prop="name" label="名称"></el-table-column>
  10. <el-table-column label="状态">
  11. <template #default="scope">
  12. <el-switch v-model="scope.row.state"
  13. inline-prompt
  14. style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949"
  15. active-text="已激活"
  16. inactive-text="已停用"
  17. active-value="ACTIVATED"
  18. inactive-value="DEACTIVATED"
  19. @change="(val) => handleStateChange(scope.row.id, val)"
  20. ></el-switch>
  21. </template>
  22. </el-table-column>
  23. <el-table-column label="金额">
  24. <template #default="scope">
  25. {{ moneyStyle(scope.row.value) }}
  26. </template>
  27. </el-table-column>
  28. <el-table-column prop="totalQuantity" label="总量"></el-table-column>
  29. <el-table-column prop="leftQuantity" label="余量"></el-table-column>
  30. <el-table-column prop="effectiveDays" label="有效天数"></el-table-column>
  31. <el-table-column prop="createTime" label="创建时间"></el-table-column>
  32. <el-table-column prop="staffName" label="创建人"></el-table-column>
  33. <el-table-column>
  34. <template #default="scope">
  35. <el-button title="编辑" type="primary" circle icon="Edit" @click="editCoupon(scope.row)"></el-button>
  36. </template>
  37. </el-table-column>
  38. </el-table>
  39. <el-dialog v-model="showEditPanel" title="编辑优惠券" width="410px">
  40. <div class="edit-coupon-line">
  41. <div class="edit-coupon-line_label">名称:</div>
  42. <div>
  43. <el-input v-model="currentCoupon.name" style="width: 180px"></el-input>
  44. </div>
  45. </div>
  46. <div class="edit-coupon-line">
  47. <div class="edit-coupon-line_label">状态:</div>
  48. <div>
  49. <el-switch v-model="currentCoupon.state"
  50. inline-prompt
  51. style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949"
  52. active-text="激活"
  53. inactive-text="停用"
  54. active-value="ACTIVATED"
  55. inactive-value="DEACTIVATED"
  56. ></el-switch>
  57. </div>
  58. </div>
  59. <div class="edit-coupon-line">
  60. <div class="edit-coupon-line_label">金额:</div>
  61. <div>
  62. <el-input-number v-model="currentCoupon.value" :min="1" :controls="false"
  63. :step="1" step-strictly style="width: 180px"></el-input-number>
  64. </div>
  65. </div>
  66. <div class="edit-coupon-line">
  67. <div class="edit-coupon-line_label">总量:</div>
  68. <div>
  69. <el-input-number v-model="currentCoupon.totalQuantity" :min="1"
  70. :step="1" step-strictly style="width: 180px"
  71. @change="handleTotalQuantityChange"
  72. :controls="false"
  73. ></el-input-number>
  74. </div>
  75. </div>
  76. <div class="edit-coupon-line">
  77. <div class="edit-coupon-line_label">余量:</div>
  78. <div>
  79. <el-input-number v-model="currentCoupon.leftQuantity"
  80. :controls="false" disabled style="width: 180px">
  81. </el-input-number>
  82. </div>
  83. </div>
  84. <div class="edit-coupon-line">
  85. <div class="edit-coupon-line_label">有效天数:</div>
  86. <div>
  87. <el-input-number v-model="currentCoupon.effectiveDays" :min="1" :controls="false"
  88. :step="1" step-strictly style="width: 180px"></el-input-number>
  89. </div>
  90. </div>
  91. <div style="margin-top: 16px; text-align: right">
  92. <el-button type="primary" size="small" icon="Check" style="width: 80px" @click="saveEditResult">保存
  93. </el-button>
  94. </div>
  95. <div v-if="currentCoupon.type === 'SALESMAN_OPERATION'" class="salesman-wrapper">
  96. 生成运营人员专属链接:
  97. <div style="margin-top: 8px">
  98. <el-input v-model="currentCoupon.salesman" style="width: 90px"
  99. placeholder="运营人员工号" clearable></el-input>
  100. <el-button type="success" plain style="margin-left: 8px" @click="generateSalesmanLink">生成</el-button>
  101. <el-button v-if="salesman.link"
  102. type="danger" style="margin-left: 8px"
  103. plain @click="copySalesmanLink">复制链接
  104. </el-button>
  105. <el-button v-if="salesman.link"
  106. type="danger" style="margin-left: 8px"
  107. plain @click="downloadSalesmanLinkQrCode">下载链接二维码
  108. </el-button>
  109. </div>
  110. <div v-if="salesman.link"
  111. style="margin-top: 8px; width: 100%; background-color: white;color: #1D1D1D;padding: 4px 8px;overflow-wrap: break-word;">
  112. <div style="padding: 6px 0">
  113. 运营人员:{{ salesman.deptName }} - {{ salesman.name }}
  114. </div>
  115. <div style="padding: 6px 0">专属链接:
  116. <span style="color: orangered">
  117. {{ salesman.link }}
  118. </span>
  119. </div>
  120. </div>
  121. </div>
  122. </el-dialog>
  123. <el-dialog v-model="showCreatePanel" title="新增优惠券" width="410px">
  124. <div class="edit-coupon-line">
  125. <div class="edit-coupon-line_label"><span class="required">*</span>名称:</div>
  126. <div class="new-coupon-val">
  127. <el-input v-model="newCoupon.name" style="width: 180px"></el-input>
  128. </div>
  129. </div>
  130. <div class="edit-coupon-line">
  131. <div class="edit-coupon-line_label"><span class="required">*</span>状态:</div>
  132. <div>
  133. <el-switch v-model="newCoupon.state"
  134. inline-prompt
  135. style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949"
  136. active-text="激活"
  137. inactive-text="停用"
  138. active-value="ACTIVATED"
  139. inactive-value="DEACTIVATED"
  140. ></el-switch>
  141. </div>
  142. </div>
  143. <div class="edit-coupon-line">
  144. <div class="edit-coupon-line_label"><span class="required">*</span>金额:</div>
  145. <div>
  146. <el-input-number v-model="newCoupon.value" :min="1"
  147. :step="1" step-strictly style="width: 180px"></el-input-number>
  148. </div>
  149. </div>
  150. <div class="edit-coupon-line">
  151. <div class="edit-coupon-line_label"><span class="required">*</span>总量:</div>
  152. <div>
  153. <el-input-number v-model="newCoupon.totalQuantity" :min="1"
  154. :step="1" step-strictly style="width: 180px"></el-input-number>
  155. </div>
  156. </div>
  157. <div class="edit-coupon-line">
  158. <div class="edit-coupon-line_label"><span class="required">*</span>余量:</div>
  159. <div>
  160. <el-input-number v-model="newCoupon.totalQuantity" disabled style="width: 180px"></el-input-number>
  161. </div>
  162. </div>
  163. <div class="edit-coupon-line">
  164. <div class="edit-coupon-line_label"><span class="required">*</span>有效天数:</div>
  165. <div>
  166. <el-input-number v-model="newCoupon.effectiveDays" :min="1"
  167. :step="1" step-strictly style="width: 180px"></el-input-number>
  168. </div>
  169. </div>
  170. <div class="edit-coupon-line">
  171. <div class="edit-coupon-line_label"><span class="required">*</span>下发方式:</div>
  172. <div>
  173. <el-select v-model="newCoupon.type" style="width: 180px">
  174. <el-option label="系统赠送" value="SYSTEM_PROVIDE"></el-option>
  175. <el-option label="医院运营" value="SALESMAN_OPERATION"></el-option>
  176. </el-select>
  177. </div>
  178. </div>
  179. <div style="margin-top: 16px; text-align: right">
  180. <el-button type="primary" size="small" icon="Check" style="width: 80px" @click="saveNewCoupon">保存
  181. </el-button>
  182. </div>
  183. </el-dialog>
  184. </template>
  185. </page-layer>
  186. </template>
  187. <script setup>
  188. import PageLayer from "@/layout/PageLayer.vue";
  189. import {getAllCoupons, getSalesmanInfo, insertNewCoupon, updateCouponState} from "@/api/outpatient/couponmanage";
  190. import store from "@/store";
  191. import {xcMessage} from "@/utils/xiaochan-element-plus";
  192. import {copyStrFunc} from "@/utils/public";
  193. import {qrcanvas} from "qrcanvas";
  194. import {ref} from "vue";
  195. const windowSize = store.state.app.windowSize
  196. const tableHeight = windowSize.h - 50
  197. const coupons = ref([])
  198. function handleStateChange(id, state) {
  199. updateCouponState({id, state})
  200. }
  201. const currentCoupon = ref({})
  202. const showEditPanel = ref(false)
  203. function editCoupon(coupon) {
  204. currentCoupon.value = coupon
  205. showEditPanel.value = true
  206. salesman.value = {}
  207. }
  208. function handleTotalQuantityChange(currentValue, oldValue) {
  209. let leftQuantity = currentCoupon.value.leftQuantity
  210. let delta = currentValue - oldValue
  211. leftQuantity += delta
  212. if (leftQuantity < 0) {
  213. xcMessage.error('余量不能小于0!')
  214. currentCoupon.value.totalQuantity = oldValue
  215. return
  216. }
  217. currentCoupon.value.leftQuantity += delta;
  218. }
  219. function saveEditResult() {
  220. updateCouponState(currentCoupon.value).then((res) => {
  221. xcMessage.success(res)
  222. showEditPanel.value = false
  223. })
  224. }
  225. const showCreatePanel = ref(false)
  226. const newCoupon = ref({
  227. state: 'ACTIVATED'
  228. })
  229. function createNewCoupon() {
  230. showCreatePanel.value = true
  231. newCoupon.value = {
  232. state: 'ACTIVATED'
  233. }
  234. }
  235. function saveNewCoupon() {
  236. insertNewCoupon(newCoupon.value).then(res => {
  237. xcMessage.success(res)
  238. showCreatePanel.value = false
  239. refreshCoupons(false)
  240. })
  241. }
  242. function moneyStyle(m) {
  243. return '¥' + m.toFixed(2)
  244. }
  245. function refreshCoupons(showSuccessMessage) {
  246. getAllCoupons().then(response => {
  247. coupons.value = response
  248. if (showSuccessMessage) {
  249. xcMessage.success('刷新数据成功')
  250. }
  251. })
  252. }
  253. const salesman = ref({})
  254. function generateSalesmanLink() {
  255. getSalesmanInfo(currentCoupon.value.salesman).then(info => {
  256. salesman.value = info
  257. let identifyCode = currentCoupon.value.id + '-' + info.code + '-' + new Date().getTime()
  258. salesman.value.link = 'https://open.weixin.qq.com/connect/oauth2/authorize?' +
  259. 'appid=wxbde6b16acad84204&redirect_uri=http://staticweb.hnthyy.cn/wxserver/redirect/page2?' +
  260. 'to=receiveCoupon_' + btoa(identifyCode) + '&response_type=code&scope=snsapi_base&state=1#wechat_redirect'
  261. })
  262. }
  263. function copySalesmanLink() {
  264. copyStrFunc(salesman.value.link)
  265. }
  266. function downloadSalesmanLinkQrCode() {
  267. const canvas = qrcanvas({
  268. data: salesman.value.link,
  269. size: 360,
  270. })
  271. let a = document.createElement('a')
  272. let event = new MouseEvent('click')
  273. a.download = salesman.value.name + '-优惠券运营'
  274. a.href = canvas.toDataURL()
  275. a.dispatchEvent(event)
  276. }
  277. onMounted(() => {
  278. refreshCoupons(false)
  279. })
  280. </script>
  281. <style scoped>
  282. .edit-coupon-line {
  283. display: flex;
  284. align-items: center;
  285. margin-bottom: 8px;
  286. }
  287. .edit-coupon-line_label {
  288. width: 80px;
  289. }
  290. .required {
  291. margin-right: 4px;
  292. color: red;
  293. }
  294. .salesman-wrapper {
  295. margin-top: 20px;
  296. background-image: linear-gradient(#247e76, #004749);
  297. color: white;
  298. padding: 8px;
  299. border-radius: 4px;
  300. }
  301. </style>