index.php 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  1. <?php
  2. use common\helpers\ComponentHelper;
  3. ComponentHelper::loadComponentView('com-share-pop');
  4. ?>
  5. <div id="app" v-cloak>
  6. <el-card shadow="never" style="border:0;" body-style="background-color: #f3f3f3;padding: 10px 0 0;">
  7. <div slot="header">
  8. <div>
  9. <span>次卡列表</span>
  10. <el-form size="small" :inline="true" style="float: right;margin-top: -5px;">
  11. <el-form-item>
  12. <el-button type="primary" size="small" style="padding: 9px 15px !important;" @click="toAdd()">新建次卡
  13. </el-button>
  14. </el-form-item>
  15. </el-form>
  16. </div>
  17. </div>
  18. <div class="table-body">
  19. 次卡名称:
  20. <div class="input-item">
  21. <el-input @keyup.enter.native="search" size="small" placeholder="请输入次卡名称" v-model="searchData.name" clearable @clear="search"></el-input>
  22. </div>
  23. 状态:
  24. <el-select size="small" v-model="searchData.is_on_sales" @change='search' class="select" style="float:none;width: 140px;">
  25. <el-option key="" label="全部" value=""></el-option>
  26. <el-option key="0" label="下架" value="0"></el-option>
  27. <el-option key="1" label="正常" value="1"></el-option>
  28. </el-select>
  29. 选择日期:
  30. <el-date-picker
  31. size="small"
  32. v-model="searchData.date_time"
  33. type="datetimerange"
  34. range-separator="至"
  35. start-placeholder="开始时间"
  36. end-placeholder="结束时间"
  37. value-format="yyyy-MM-dd HH:mm:ss"
  38. >
  39. </el-date-picker>
  40. <div style="display: inline-block;margin-left: 10px;">
  41. <el-button type="primary" size="small" @click="search">查询</el-button>
  42. <el-button type="primary" size="small" @click="resetForm" style=" margin-left: 0px;background-color: #ef1818;border-color: #ef1818;">重置</el-button>
  43. </div>
  44. </div>
  45. <div class="table-body">
  46. <template>
  47. <el-table ref="multipleTable" :data="list" @sort-change="sortChange"
  48. >
  49. <!-- 空数据 -->
  50. <template slot="empty">
  51. <el-empty description="暂无数据"></el-empty>
  52. </template>
  53. <el-table-column prop="id" label="id" align="center"></el-table-column>
  54. <el-table-column prop="name" label="次卡名称" align="center"></el-table-column>
  55. <el-table-column prop="store_counts" label="适用门店" align="center">
  56. <template slot-scope="scope">
  57. <el-button @click="showCanClerkStore(scope.row.id,scope.row.name)" type="text" size="small">{{scope.row.store_counts}}</el-button>
  58. </template>
  59. </el-table-column>
  60. <el-table-column prop="max_times" label="库存" align="center" sortable="max_times"></el-table-column>
  61. <el-table-column prop="total_redemption" label="累计兑卡张数" align="center" sortable="total_redemption"></el-table-column>
  62. <el-table-column prop="total_sales" label="累计售卡数" align="center" sortable="total_sales"></el-table-column>
  63. <el-table-column prop="total_sales_price" label="累计售卡金额" align="center" sortable="total_sales_price"></el-table-column>
  64. <el-table-column prop="source" label="创建来源" align="center"></el-table-column>
  65. <el-table-column prop="is_on_sales" label="次卡状态" align="center">
  66. <template slot-scope="scope">
  67. <div v-if="scope.row.is_on_sales ==0">
  68. 下架
  69. </div>
  70. <div v-else>
  71. 正常
  72. </div>
  73. </template>
  74. </el-table-column>
  75. <el-table-column label="创建时间" prop="created_at" align="center" width="200" sortable="created_at">
  76. <template slot-scope="scope">
  77. {{scope.row.created_at|dateTimeFormat('Y-m-d H:i:s')}}
  78. </template>
  79. </el-table-column>
  80. <el-table-column align="center" label="操作" width="200">
  81. <template slot-scope="scope">
  82. <el-button @click="toPromotion(scope.row)" type="text" size="small">推广</el-button>
  83. <el-button @click="toEdit(scope.row)" type="text" size="small">编辑</el-button>
  84. <el-button @click="toRedemptionCode(scope.row.id)" type="text" size="small">兑换码</el-button>
  85. <el-dropdown style="margin-left: 10px">
  86. <el-button type="text" class="el-dropdown-link">
  87. 更多<i class="el-icon-arrow-down el-icon--right"></i>
  88. </el-button>
  89. <el-dropdown-menu slot="dropdown">
  90. <el-dropdown-item v-if="scope.row.is_on_sales==1">
  91. <div style="width: 100%; height: 100%;" @click="changeIsOnSales(scope.row.id)">
  92. <el-button type="text" class="copy_btn">下架</el-button>
  93. </div>
  94. </el-dropdown-item>
  95. <el-dropdown-item v-if="scope.row.is_on_sales==0">
  96. <div style="width: 100%; height: 100%;" @click="uploadIsOnSales(scope.row.id)">
  97. <el-button type="text" class="copy_btn">上架</el-button>
  98. </div>
  99. </el-dropdown-item>
  100. <el-dropdown-item>
  101. <el-button @click="toOrder(scope.row.name,scope.row.id)" type="text" size="small">记录</el-button>
  102. </el-dropdown-item>
  103. </el-dropdown-menu>
  104. </el-dropdown>
  105. </template>
  106. </el-table-column>
  107. </el-table>
  108. </template>
  109. <!-- 分页 -->
  110. <el-row type="flex" class="page" justify="end">
  111. <el-pagination @current-change="pagination" background layout="prev, pager, next" :page-count="pageCount" v-if="list"></el-pagination>
  112. </el-row>
  113. </div>
  114. <el-dialog title="可核销店铺" :visible.sync="dialogContent" :before-close="handleClose">
  115. 权益卡:{{secondary_card_name}}
  116. <el-table :data="gridData">
  117. <el-table-column property="store_name" label="店铺名称" width="150" align="center"></el-table-column>
  118. <el-table-column property="type_text" label="类型" align="center"></el-table-column>
  119. <el-table-column property="address" label="地址" align="center"></el-table-column>
  120. <el-table-column label="店长/联系方式" width="200" align="center">
  121. <template slot-scope="scope">
  122. {{scope.row.shop_owner}}</br>
  123. {{scope.row.shop_mobile}}</br>
  124. </template>
  125. </el-table-column>
  126. </el-table>
  127. <el-row type="flex" class="page" justify="end">
  128. <el-pagination @current-change="paginationClerkStore" background layout="prev, pager, next" :page-count="pageCountClerk" v-if="list"></el-pagination>
  129. </el-row>
  130. </el-dialog>
  131. <el-dialog title="推广二维码/链接(使用对应的APP扫码,即可访问内容详情)" :visible.sync="dialogVisible" width="40%">
  132. <el-tabs :tab-position="tabPosition">
  133. <el-tab-pane label="微信公众号" class="flex-x-centet">
  134. <div style="width: 180px; height: 180px;background: #F2F2F2;margin-right: 12px;" flex="main:center cross:center">
  135. <el-image id="code-img" style="width: 144px; height: 144px;" :src="qrCodeImg"></el-image>
  136. </div>
  137. <el-button flex type="text" @click="downloadShareImg('qrcode')">下载二维码</el-button>
  138. <template>
  139. <span id="target"> {{promotion_code}}
  140. &nbsp;<el-button type="text" id="copy_btn" data-clipboard-action="copy" data-clipboard-target="#target" size="mini">复制</el-button>
  141. </span>
  142. </template>
  143. </el-tab-pane>
  144. <el-tab-pane label="微信小程序" class="flex-x-centet">
  145. <div style="width: 180px; height: 180px;background: #F2F2F2;margin-right: 12px;" flex="main:center cross:center">
  146. <el-image id="code-img" style="width: 144px; height: 144px;" :src="applet_code"></el-image>
  147. </div>
  148. <el-button flex type="text" @click="downloadShareImg('mini_qrcode')">下载二维码</el-button>
  149. </el-tab-pane>
  150. </el-tabs>
  151. </el-dialog>
  152. <div id="qrcode" style="width:100px; height:100px; margin-top:15px; display: none"></div>
  153. </div>
  154. </el-card>
  155. </div>
  156. <script>
  157. const app = new Vue({
  158. el: '#app',
  159. data() {
  160. return {
  161. loading: false,
  162. list: [],
  163. searchData: {
  164. name: '',
  165. is_on_sales: '',
  166. date_time: '',
  167. },
  168. pageCount: 0,
  169. page: 1,
  170. currentPage: null,
  171. listLoading: false,
  172. type: '',
  173. sort: '',
  174. sort_column:'',
  175. sort_order:'',
  176. dialogContent:false,
  177. gridData: [],
  178. secondary_card_name: '',
  179. secondary_card_id: '',
  180. page_clerk: 1,
  181. pageCountClerk: 0,
  182. currentPageClerk: null,
  183. dialogVisible: false,
  184. tabPosition:'left',
  185. qrCodeImg:"",
  186. applet_code:"",
  187. promotion_code:""
  188. };
  189. },
  190. created() {
  191. this.searchData.order_no = getQuery('order_no')
  192. },
  193. methods: {
  194. //搜索
  195. search() {
  196. this.page = 1;
  197. this.loadData();
  198. },
  199. pagination(currentPage) {
  200. this.page = currentPage;
  201. this.loadData();
  202. },
  203. loadData() {
  204. this.listLoading = true;
  205. var param = {
  206. r: 'secondary-card/default/index',
  207. page: this.page,
  208. name: this.searchData.name,
  209. is_on_sales: this.searchData.is_on_sales,
  210. date_time: this.searchData.date_time,
  211. sort_column:this.sort_column,
  212. sort_order:this.sort_order,
  213. limit: 15
  214. }
  215. request({
  216. params: param,
  217. }).then(e => {
  218. if (e.data.code === 0) {
  219. this.list = e.data.data.list;
  220. this.pageCount = e.data.data.page_count;
  221. this.currentPage = e.data.data.pagination.current_page;
  222. } else {
  223. this.$message.error(e.data.msg);
  224. }
  225. this.listLoading = false;
  226. }).catch(e => {
  227. this.listLoading = false;
  228. });
  229. },
  230. //重置
  231. resetForm() {
  232. this.searchData.is_on_sales = '';
  233. this.searchData.date_time = '';
  234. this.searchData.name = '';
  235. },
  236. toAdd(){
  237. this.$navigate({
  238. r: 'secondary-card/default/edit'
  239. })
  240. },
  241. toEdit(row){
  242. this.$navigate({
  243. r: 'secondary-card/default/edit',
  244. id: row.id,
  245. use_type:row.use_type
  246. })
  247. },
  248. toRedemptionCode(id){
  249. this.$navigate({
  250. r: 'secondary-card/default/redemption-code',
  251. id: id
  252. })
  253. },
  254. toOrder(secondary_card_name,id){
  255. this.$navigate({
  256. r: 'secondary-card/default/order',
  257. secondary_card_name: secondary_card_name,
  258. secondary_card_id: id,
  259. })
  260. },
  261. sortChange( column, prop, order){
  262. this.sort_order = column.order;
  263. this.sort_column = column.prop;
  264. this.loadData();
  265. },
  266. handleClose(done) {
  267. this.page_clerk= 1;
  268. this.pageCountClerk=0;
  269. this.currentPageClerk=null;
  270. this.dialogContent = false;
  271. },
  272. changeIsOnSales(id){
  273. let self = this;
  274. self.$confirm('是否下架该次卡?', '警告', {
  275. type: 'warning'
  276. }).then(() => {
  277. request({
  278. params: {
  279. r: 'secondary-card/default/change-is-on-sales',
  280. },
  281. method: 'post',
  282. data: {
  283. id: id,
  284. is_on_sales: 0,
  285. },
  286. }).then(e => {
  287. if (e.data.code == 0) {
  288. self.$message.success(e.data.msg);
  289. self.loadData();
  290. } else {
  291. self.$message.error(e.data.msg);
  292. }
  293. }).catch(e => {
  294. console.log(e);
  295. });
  296. })
  297. },
  298. uploadIsOnSales(id){
  299. let self = this;
  300. self.$confirm('是否上架该次卡?', '警告', {
  301. type: 'warning'
  302. }).then(() => {
  303. request({
  304. params: {
  305. r: 'secondary-card/default/upload-is-on-sales',
  306. },
  307. method: 'post',
  308. data: {
  309. id: id,
  310. is_on_sales: 1,
  311. },
  312. }).then(e => {
  313. if (e.data.code == 0) {
  314. self.$message.success(e.data.msg);
  315. self.loadData();
  316. } else {
  317. self.$message.error(e.data.msg);
  318. }
  319. }).catch(e => {
  320. console.log(e);
  321. });
  322. })
  323. },
  324. showCanClerkStore(secondary_card_id,secondary_card_name){
  325. this.secondary_card_name =secondary_card_name;
  326. this.secondary_card_id = secondary_card_id;
  327. this.dialogContent = true;
  328. var param = {
  329. r: 'secondary-card/default/can-clerk-store-list',
  330. page: this.page_clerk,
  331. id: secondary_card_id,
  332. limit: 15
  333. }
  334. request({
  335. params: param,
  336. }).then(e => {
  337. if (e.data.code === 0) {
  338. this.gridData = e.data.data.list;
  339. this.pageCountClerk = e.data.data.page_count;
  340. this.currentPageClerk = e.data.data.pagination.current_page;
  341. } else {
  342. this.$message.error(e.data.msg);
  343. }
  344. this.listLoading = false;
  345. }).catch(e => {
  346. this.listLoading = false;
  347. });
  348. },
  349. paginationClerkStore(currentPage) {
  350. this.page_clerk = currentPage;
  351. this.showCanClerkStore(this.secondary_card_id ,this.secondary_card_name );
  352. },
  353. toPromotion(row){
  354. this.dialogVisible = true;
  355. let qrCodeDom = document.getElementById("qrcode")
  356. var qrcode = new QRCode(qrCodeDom, {
  357. width : 100,
  358. height : 100
  359. });
  360. var url = row.promotion_code;
  361. console.log(url,11111)
  362. this.promotion_code = url;
  363. qrcode.makeCode(url);
  364. let src = "";
  365. if(row.applet_code==''){
  366. request({
  367. params: {
  368. r: 'secondary-card/default/show-mini-promotion-code',
  369. },
  370. method: 'post',
  371. data: {
  372. id: row.id,
  373. },
  374. }).then(e => {
  375. if (e.data.code == 0) {
  376. this.applet_code = e.data.data.applet_code;
  377. } else {
  378. }
  379. }).catch(e => {
  380. console.log(e);
  381. });
  382. }else{
  383. this.applet_code = row.applet_code;
  384. }
  385. return new Promise((req, rej) => {
  386. setTimeout(() => {
  387. let img_arr = qrCodeDom.getElementsByTagName("img");
  388. let len = img_arr.length;
  389. src = img_arr[len-1].src;
  390. this.qrCodeImg = src
  391. req(src)
  392. }, 10);
  393. })
  394. },
  395. // 图片下载
  396. downloadShareImg(type, img) {
  397. let img_url = img;
  398. if ('qrcode' == type) {
  399. img_url = this.qrCodeImg;
  400. }
  401. if ('mini_qrcode' == type) {
  402. img_url = this.applet_code;
  403. }
  404. fetch(img_url).then(res => res.blob().then(blob => {
  405. var a = document.createElement('a');
  406. var url = window.URL.createObjectURL(blob);
  407. a.href = url;
  408. a.download = "";
  409. a.click();
  410. window.URL.revokeObjectURL(url);
  411. }))
  412. },
  413. },
  414. mounted: function() {
  415. this.page = getQuery('page') ? getQuery('page') : 1;
  416. this.loadData();
  417. },
  418. });
  419. var clipboard = new ClipboardJS('#copy_btn');
  420. var self = this;
  421. clipboard.on('success', function(e) {
  422. self.ELEMENT.Message.success('复制成功');
  423. e.clearSelection();
  424. });
  425. clipboard.on('error', function(e) {
  426. self.ELEMENT.Message.success('复制失败,请手动复制');
  427. });
  428. </script>
  429. <style>
  430. .table-body {
  431. padding: 20px;
  432. background-color: #fff;
  433. }
  434. /* .table-info .el-button {
  435. padding: 0 !important;
  436. border: 0;
  437. margin: 0 5px;
  438. } */
  439. .input-item {
  440. display: inline-block;
  441. width: 150px;
  442. margin: 0 0 20px;
  443. margin-right: 10px;
  444. }
  445. .input-item .el-input__inner {
  446. border-right: 1px solid #dcdfe6;
  447. }
  448. .input-item .el-input__inner:hover {
  449. border: 1px solid #dcdfe6;
  450. border-right: 0;
  451. outline: 0;
  452. }
  453. .input-item .el-input__inner:focus {
  454. border: 1px solid #dcdfe6;
  455. border-right: 0;
  456. outline: 0;
  457. }
  458. .input-item .el-input-group__append {
  459. background-color: #fff;
  460. border-left: 0;
  461. width: 10%;
  462. padding: 0;
  463. }
  464. .input-item .el-input-group__append .el-button {
  465. padding: 0;
  466. }
  467. .input-item .el-input-group__append .el-button {
  468. margin: 0;
  469. }
  470. .select {
  471. float: left;
  472. width: 100px;
  473. margin-right: 10px;
  474. }
  475. .el-table th>.cell {
  476. color: #333;
  477. font-weight: bold;
  478. font-size: 14px;
  479. }
  480. .el-table__footer-wrapper,
  481. .el-table__header-wrapper {
  482. border-bottom: 1.4px solid #D6D6D6;
  483. }
  484. .search-sort {
  485. display: inline-block;
  486. margin: 0px 10px;
  487. cursor: pointer;
  488. color: rgb(51, 51, 51);
  489. }
  490. .caret-wrapper {
  491. display: inline-flex;
  492. flex-direction: column;
  493. align-items: center;
  494. height: 25px;
  495. width: 11px;
  496. vertical-align: middle;
  497. cursor: pointer;
  498. overflow: initial;
  499. position: relative;
  500. }
  501. .caret-top {
  502. border: 5px solid transparent;
  503. margin: 1px 0;
  504. border-bottom-color: rgb(51, 51, 51);
  505. }
  506. .caret-bottom {
  507. border: 5px solid transparent;
  508. margin: 1px 0;
  509. border-top-color: rgb(51, 51, 51);
  510. }
  511. .active {
  512. border-top-color: rgb(41, 186, 156);
  513. }
  514. .ellipsis {
  515. font-size: 14px;
  516. color: #333;
  517. overflow: hidden;
  518. text-overflow: ellipsis;
  519. }
  520. .goods-wrapper {
  521. border: 2px solid #CCCCCC;
  522. display: inline-block
  523. }
  524. .goods-select {
  525. border: 2px solid #bb730c;
  526. }
  527. .goods-price {
  528. text-align: center;
  529. }
  530. .goods-price .number {
  531. color: red;
  532. font-weight: 600;
  533. font-size: 18px;
  534. }
  535. .goods-price .title {
  536. padding: 5px 0;
  537. color: #999;
  538. ;
  539. font-size: 10px;
  540. font-weight: 600;
  541. }
  542. .bottom-price .title {
  543. padding: 5px 0;
  544. color: #8b8888;
  545. ;
  546. font-size: 10px;
  547. }
  548. .bottom-price .number {
  549. color: #ff5100;
  550. font-size: 10px;
  551. }
  552. .goods-action {
  553. margin-top: 8px;
  554. }
  555. .goods-action .title {
  556. color: #0634aa;
  557. }
  558. .bottom-active {
  559. border-bottom-color: rgb(186, 41, 92);
  560. }
  561. .top-active {
  562. border-top-color: rgb(186, 41, 92);
  563. }
  564. .price {
  565. white-space: nowrap;
  566. }
  567. .goods-image {
  568. display: flex;
  569. justify-content: center;
  570. }
  571. .page {
  572. padding: 10px 0;
  573. }
  574. .flex-x-centet{
  575. display: flex;
  576. flex-direction: column;
  577. align-items: center;
  578. }
  579. </style>