coupon.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  1. define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) {
  2. var Controller = {
  3. index: () => {
  4. const { reactive, onMounted } = Vue
  5. const index = {
  6. setup() {
  7. const state = reactive({
  8. data: [],
  9. order: '',
  10. sort: '',
  11. filter: {
  12. drawer: false,
  13. data: {
  14. keyword: '',
  15. type: '',
  16. use_scope: '',
  17. },
  18. tools: {
  19. keyword: {
  20. type: 'tinput',
  21. label: '查询内容',
  22. placeholder: '请输入查询内容',
  23. value: '',
  24. },
  25. type: {
  26. type: 'tselect',
  27. label: '类型',
  28. value: '',
  29. options: {
  30. data: [{
  31. label: '满减券',
  32. value: 'reduce',
  33. },
  34. {
  35. label: '折扣券',
  36. value: 'discount',
  37. }],
  38. },
  39. },
  40. use_scope: {
  41. type: 'tselect',
  42. label: '可用范围',
  43. value: '',
  44. options: {
  45. data: [{
  46. label: '全场通用',
  47. value: 'all_use',
  48. },
  49. {
  50. label: '指定商品可用',
  51. value: 'goods',
  52. },
  53. {
  54. label: '指定商品不可用',
  55. value: 'disabled_goods',
  56. },
  57. {
  58. label: '指定分类可用',
  59. value: 'category',
  60. }],
  61. },
  62. },
  63. },
  64. condition: {},
  65. },
  66. dashboard: {
  67. total_num: {
  68. name: '总发券量/张',
  69. num: '',
  70. tip: '用户领取的优惠券的总张数,包含已经被后台删除的优惠券'
  71. },
  72. expire_num: {
  73. name: '已过期/张',
  74. num: '',
  75. tip: '用户已领取的并且已经超过可使用日期的未使用优惠券'
  76. },
  77. use_num: {
  78. name: '已使用/张',
  79. num: '',
  80. tip: '用户已领取并且已使用的优惠券',
  81. },
  82. use_percent: {
  83. name: '使用率',
  84. num: '',
  85. tip: '用户已使用优惠和总发券量的比例'
  86. },
  87. }
  88. })
  89. function getData() {
  90. let tempSearch = JSON.parse(JSON.stringify(state.filter.data));
  91. let search = composeFilter(tempSearch, {
  92. keyword: 'like',
  93. });
  94. Fast.api.ajax({
  95. url: 'shopro/coupon',
  96. type: 'GET',
  97. data: {
  98. page: pagination.page,
  99. list_rows: pagination.list_rows,
  100. order: state.order,
  101. sort: state.sort,
  102. ...search,
  103. },
  104. }, function (ret, res) {
  105. state.data = res.data.coupons.data
  106. pagination.total = res.data.coupons.total
  107. for (var key in state.dashboard) {
  108. state.dashboard[key].num = res.data[key]
  109. }
  110. return false
  111. }, function (ret, res) { })
  112. }
  113. function onChangeSort({ prop, order }) {
  114. state.order = order == 'ascending' ? 'asc' : 'desc';
  115. state.sort = prop;
  116. getData();
  117. }
  118. function onOpenFilter() {
  119. state.filter.drawer = true
  120. }
  121. function onChangeFilter() {
  122. pagination.page = 1
  123. getData()
  124. state.filter.drawer && (state.filter.drawer = false)
  125. }
  126. const pagination = reactive({
  127. page: 1,
  128. list_rows: 10,
  129. total: 0,
  130. })
  131. async function onCommand(item) {
  132. Fast.api.ajax({
  133. url: `shopro/coupon/edit/id/${item.id}`,
  134. type: 'POST',
  135. data: {
  136. status: item.type
  137. },
  138. }, function (ret, res) {
  139. getData();
  140. }, function (ret, res) { })
  141. }
  142. function onAdd() {
  143. Fast.api.open(`shopro/coupon/add?type=add`, "添加", {
  144. callback() {
  145. getData()
  146. }
  147. })
  148. }
  149. function onEdit(id) {
  150. Fast.api.open(`shopro/coupon/edit?type=edit&id=${id}`, "编辑", {
  151. callback() {
  152. getData()
  153. }
  154. })
  155. }
  156. function onDelete(id) {
  157. Fast.api.ajax({
  158. url: `shopro/coupon/delete/id/${id}`,
  159. type: 'DELETE',
  160. }, function (ret, res) {
  161. getData()
  162. }, function (ret, res) { })
  163. }
  164. function onRecyclebin() {
  165. Fast.api.open(`shopro/coupon/recyclebin`, "回收站", {
  166. callback() {
  167. getData()
  168. }
  169. })
  170. }
  171. function onCoupon(id) {
  172. Fast.api.addtabs(`shopro/user/coupon?coupon_id=${id}`, '领取记录')
  173. }
  174. function onSend(id) {
  175. Fast.api.open(`shopro/user/user/select?id=${id}`, '选择用户', {
  176. callback() {
  177. getData()
  178. }
  179. })
  180. }
  181. onMounted(() => {
  182. getData()
  183. })
  184. return {
  185. state,
  186. getData,
  187. onChangeSort,
  188. onOpenFilter,
  189. onChangeFilter,
  190. pagination,
  191. onCommand,
  192. onAdd,
  193. onEdit,
  194. onDelete,
  195. onRecyclebin,
  196. onCoupon,
  197. onSend,
  198. }
  199. }
  200. }
  201. createApp('index', index);
  202. },
  203. add: () => {
  204. Controller.form();
  205. },
  206. edit: () => {
  207. Controller.form();
  208. },
  209. form: () => {
  210. const { reactive, onMounted, getCurrentInstance } = Vue
  211. const { ElMessage } = ElementPlus
  212. const addEdit = {
  213. setup() {
  214. const { proxy } = getCurrentInstance();
  215. const state = reactive({
  216. type: new URLSearchParams(location.search).get('type'),
  217. id: new URLSearchParams(location.search).get('id'),
  218. })
  219. const form = reactive({
  220. model: {
  221. name: '',
  222. type: 'reduce', // 优惠券类型:reduce=满减券,discount=折扣券
  223. use_scope: 'all_use', // 可用范围:all=全场通用,goods=指定商品可用,disabled_goods=指定商品不可用,category=指定分类可用
  224. items: '',
  225. items_value: [],
  226. amount: '',
  227. max_amount: '',
  228. enough: '',
  229. stock: '',
  230. limit_num: '',
  231. get_time: '',
  232. use_time_type: 'days',
  233. use_time: '',
  234. start_days: '',
  235. days: '',
  236. is_double_discount: '',
  237. description: '',
  238. status: 'normal', // 状态:normal=公开,hidden=后台发放,disabled=禁用
  239. },
  240. rules: {
  241. name: [{ required: true, message: '请输入券名称', trigger: 'blur' }],
  242. type: [{ required: true, message: '请选择券类型', trigger: 'blur' }],
  243. enough: [{ required: true, message: '请输入消费门槛', trigger: 'blur' }],
  244. amount: [{ required: true, message: '请输入使用面额', trigger: 'blur' }],
  245. max_amount: [{ required: true, message: '请输入最大优惠', trigger: 'blur' }],
  246. stock: [{ required: true, message: '请输入发券总量', trigger: 'blur' }],
  247. get_time: [{ required: true, message: '请选择优惠券发放时间', trigger: 'blur' }],
  248. use_time: [{ required: true, message: '请选择优惠券可使用时间', trigger: 'blur' }],
  249. use_time_type: [{ required: true, message: '请选择优惠券使用时间类型', trigger: 'blur' }],
  250. days: [{ required: true, message: '请输入优惠券有效天数', trigger: 'blur' }],
  251. use_scope: [{ required: true, message: '请选择可用范围', trigger: 'blur' }],
  252. },
  253. });
  254. function getDetail() {
  255. Fast.api.ajax({
  256. url: `shopro/coupon/detail/id/${state.id}`,
  257. type: 'GET',
  258. }, function (ret, res) {
  259. form.model = res.data;
  260. form.model.get_time = [form.model.get_start_time, form.model.get_end_time];
  261. if (form.model.use_time_type == 'days') {
  262. form.model.use_time = '';
  263. } else if (form.model.use_time_type == 'range') {
  264. form.model.use_time = [form.model.use_start_time, form.model.use_end_time];
  265. }
  266. return false
  267. }, function (ret, res) { })
  268. }
  269. function onSelectGoods() {
  270. let ids = [];
  271. form.model.items_value.forEach((i) => {
  272. ids.push(i.id);
  273. });
  274. Fast.api.open(`shopro/goods/goods/select?multiple=true&ids=${ids.join(',')}`, "选择商品", {
  275. callback(data) {
  276. form.model.items_value = data;
  277. }
  278. })
  279. }
  280. function onDeleteGoods(index) {
  281. form.model.items_value.splice(index, 1);
  282. }
  283. function onSelectCategory() {
  284. let ids = [];
  285. form.model.items_value.forEach((i) => {
  286. ids.push(i.id);
  287. });
  288. Fast.api.open(`shopro/category/select?from=coupon&multiple=true`, "选择分类", {
  289. callback(data) {
  290. form.model.items_value = data.data;
  291. }
  292. })
  293. }
  294. function onDeleteCategory(index) {
  295. form.model.items_value.splice(index, 1);
  296. }
  297. function onConfirm() {
  298. proxy.$refs['formRef'].validate((valid) => {
  299. if (valid) {
  300. let submitForm = JSON.parse(JSON.stringify(form.model));
  301. if (Number(submitForm.enough) < Number(submitForm.amount)) {
  302. ElMessage({
  303. message: '请输入正确的使用门槛',
  304. type: 'warning',
  305. });
  306. return;
  307. }
  308. if (
  309. submitForm.use_scope == 'goods' ||
  310. submitForm.use_scope == 'disabled_goods' ||
  311. submitForm.use_scope == 'category'
  312. ) {
  313. let ids = [];
  314. submitForm.items_value.forEach((i) => {
  315. ids.push(i.id);
  316. });
  317. submitForm.items = ids.join(',');
  318. } else if (submitForm.use_scope == 'all_use') {
  319. submitForm.items = '';
  320. }
  321. delete submitForm.items_value;
  322. if (!isEmpty(submitForm.use_time)) {
  323. submitForm.use_time = submitForm.use_time.join(' - ');
  324. }
  325. if (!isEmpty(submitForm.get_time)) {
  326. submitForm.get_time = submitForm.get_time.join(' - ');
  327. }
  328. Fast.api.ajax({
  329. url: state.type == 'add' ? 'shopro/coupon/add' : `shopro/coupon/edit/id/${state.id}`,
  330. type: 'POST',
  331. data: submitForm
  332. }, function (ret, res) {
  333. Fast.api.close()
  334. }, function (ret, res) { })
  335. }
  336. });
  337. }
  338. onMounted(() => {
  339. state.type == 'edit' && getDetail()
  340. })
  341. return {
  342. state,
  343. form,
  344. onSelectGoods,
  345. onDeleteGoods,
  346. onSelectCategory,
  347. onDeleteCategory,
  348. onConfirm
  349. }
  350. }
  351. }
  352. createApp('addEdit', addEdit);
  353. },
  354. select: () => {
  355. const { reactive, onMounted } = Vue
  356. const select = {
  357. setup() {
  358. const state = reactive({
  359. multiple: new URLSearchParams(location.search).get('multiple') || false,
  360. status: new URLSearchParams(location.search).get('status'),
  361. data: [],
  362. selected: [],
  363. })
  364. function getData() {
  365. let tempSearch = {
  366. status: state.status
  367. };
  368. let search = composeFilter(tempSearch);
  369. Fast.api.ajax({
  370. url: 'shopro/coupon/select',
  371. type: 'GET',
  372. data: {
  373. page: pagination.page,
  374. list_rows: pagination.list_rows,
  375. ...search,
  376. },
  377. }, function (ret, res) {
  378. state.data = res.data.data
  379. pagination.total = res.data.total
  380. return false
  381. }, function (ret, res) { })
  382. }
  383. const pagination = reactive({
  384. page: 1,
  385. list_rows: 10,
  386. total: 0,
  387. })
  388. function onSelect(item) {
  389. Fast.api.close(item)
  390. }
  391. function onChangeSelection(val) {
  392. state.selected = val
  393. }
  394. function onConfirm() {
  395. Fast.api.close(state.selected)
  396. }
  397. onMounted(() => {
  398. getData()
  399. })
  400. return {
  401. state,
  402. getData,
  403. pagination,
  404. onSelect,
  405. onChangeSelection,
  406. onConfirm,
  407. }
  408. }
  409. }
  410. createApp('select', select);
  411. },
  412. recyclebin: () => {
  413. const { reactive, onMounted } = Vue
  414. const { ElMessageBox } = ElementPlus
  415. const recyclebin = {
  416. setup() {
  417. const state = reactive({
  418. data: [],
  419. order: '',
  420. sort: '',
  421. })
  422. function getData() {
  423. Fast.api.ajax({
  424. url: 'shopro/coupon/recyclebin',
  425. type: 'GET',
  426. data: {
  427. page: pagination.page,
  428. list_rows: pagination.list_rows,
  429. order: state.order,
  430. sort: state.sort,
  431. },
  432. }, function (ret, res) {
  433. state.data = res.data.data
  434. pagination.total = res.data.total
  435. return false
  436. }, function (ret, res) { })
  437. }
  438. function onChangeSort({ prop, order }) {
  439. state.order = order == 'ascending' ? 'asc' : 'desc';
  440. state.sort = prop;
  441. getData();
  442. }
  443. const pagination = reactive({
  444. page: 1,
  445. list_rows: 10,
  446. total: 0,
  447. })
  448. const batchHandle = reactive({
  449. data: [],
  450. })
  451. function onChangeSelection(val) {
  452. batchHandle.data = val
  453. }
  454. function onBatchHandle(type) {
  455. let ids = []
  456. batchHandle.data.forEach((item) => {
  457. ids.push(item.id)
  458. })
  459. switch (type) {
  460. case 'restore':
  461. onRestore(ids.join(','))
  462. break;
  463. case 'destroy':
  464. ElMessageBox.confirm('此操作将销毁, 是否继续?', '提示', {
  465. confirmButtonText: '确定',
  466. cancelButtonText: '取消',
  467. type: 'warning',
  468. }).then(() => {
  469. onDestroy(ids.join(','))
  470. });
  471. break;
  472. case 'all':
  473. ElMessageBox.confirm('此操作将清空回收站, 是否继续?', '提示', {
  474. confirmButtonText: '确定',
  475. cancelButtonText: '取消',
  476. type: 'warning',
  477. }).then(() => {
  478. onDestroy('all')
  479. });
  480. break;
  481. }
  482. }
  483. function onRestore(id) {
  484. Fast.api.ajax({
  485. url: `shopro/coupon/restore/id/${id}`,
  486. type: 'POST',
  487. }, function (ret, res) {
  488. getData()
  489. }, function (ret, res) { })
  490. }
  491. function onDestroy(id) {
  492. Fast.api.ajax({
  493. url: `shopro/coupon/destroy/id/${id}`,
  494. type: 'POST',
  495. }, function (ret, res) {
  496. getData()
  497. }, function (ret, res) { })
  498. }
  499. onMounted(() => {
  500. getData()
  501. })
  502. return {
  503. state,
  504. getData,
  505. onChangeSort,
  506. pagination,
  507. batchHandle,
  508. onChangeSelection,
  509. onBatchHandle,
  510. onRestore,
  511. onDestroy,
  512. }
  513. }
  514. }
  515. createApp('recyclebin', recyclebin);
  516. },
  517. };
  518. return Controller;
  519. });