index.php 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624
  1. <?php
  2. use common\helpers\AddonHelper;
  3. use common\helpers\ComponentHelper;
  4. ComponentHelper::loadComponentView('component/com-add-cat', __DIR__);
  5. ComponentHelper::loadComponentView('com-export-dialog');
  6. ?>
  7. <style>
  8. </style>
  9. <div id="app" v-cloak>
  10. <el-card shadow="never" body-style="background-color: #f3f3f3;padding: 10px 0 0;">
  11. <div slot="header">
  12. <span>商品列表</span>
  13. <div style="float: right; margin: -5px 0">
  14. <el-button type="primary" size="small" @click="handle('add')">添加商品</el-button>
  15. <com-export-dialog
  16. style="float: right;margin-left: 10px;"
  17. :field_list='export_list'
  18. :action_url="export_url"
  19. :params="search_data">
  20. </com-export-dialog>
  21. </div>
  22. </div>
  23. <div class="table-body">
  24. <el-tabs v-model="activeName" @tab-click="handleClick">
  25. <el-tab-pane v-for="item in tabs" :key="item.id" :label="item.name" :name="item.id">
  26. <el-form :inline="true" :model="search_data" size="small" class="demo-form-inline">
  27. <el-form-item>
  28. <el-button size="small" @click="$refs.cats.openDialog()">分类筛选</el-button>
  29. <el-button size="small" v-if="search_data.cats && search_data.cats.length > 0" type="danger" @click="clearCat">清除分类</el-button>
  30. </el-form-item>
  31. <el-form-item>
  32. <el-date-picker style="margin-top: 1px;" size="small" @change="changeTime" v-model="datetime" type="datetimerange" value-format="yyyy-MM-dd HH:mm:ss" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" :default-time="['00:00:00', '23:59:59']"></el-date-picker>
  33. </el-form-item>
  34. <el-form-item label="">
  35. <el-input size="small" placeholder="请输入商品名称" v-model="search_data.goods_name"></el-input>
  36. </el-form-item>
  37. <el-form-item label="">
  38. <el-input size="small" placeholder="请输入商品ID精准搜索" v-model="search_data.goods_id"></el-input>
  39. </el-form-item>
  40. <el-form-item label="">
  41. <el-select size="small" v-model="search_data.goods_type" placeholder="请选择商品类型" style="width: 100%;" clearable>
  42. <el-option label="实体商品" :value="1"></el-option>
  43. <el-option label="虚拟商品" :value="2"></el-option>
  44. <el-option label="预约商品" :value="3"></el-option>
  45. </el-select>
  46. </el-form-item>
  47. <el-form-item>
  48. <el-button type="primary" @click="search">搜索</el-button>
  49. <el-button type="danger" @click="clearSearch" v-if="show_clear_search_btn">清除条件</el-button>
  50. <el-button v-if="item.value=='all'" type="primary" @click="multipleOn">批量上架</el-button>
  51. <el-button v-if="item.value=='all'" type="primary" @click="multipleOff">批量下架</el-button>
  52. </el-form-item>
  53. </el-form>
  54. <el-table v-loading="listLoading" :data="list" stripe style="width: 100%" @sort-change="sortChange" @selection-change="handleSelectionChange">
  55. <!-- <el-table-column type="selection" align="center" width="60"></el-table-column> -->
  56. <el-table-column v-if="item.value=='all'" type="selection" align="center" :selectable="checkSelectable" > </el-table-column>
  57. <el-table-column label="ID" prop="id" align="center"></el-table-column>
  58. <!-- <el-table-column prop="sort" label="排序" width="150">
  59. <template slot-scope="scope">
  60. <div v-if="sort_id != scope.row.id">
  61. <el-tooltip class="item" effect="dark" content="排序" placement="top">
  62. <span>{{scope.row.sort}}</span>
  63. </el-tooltip>
  64. <el-button class="edit-sort" type="text" @click="edit(scope.row,'sort')">
  65. <img src="resources/img/mall/order/edit.png" alt="">
  66. </el-button>
  67. </div>
  68. <div style="display: flex;align-items: center" v-else>
  69. <el-input style="min-width: 70px" type="number" size="mini" class="change" v-model="sort" autocomplete="off"></el-input>
  70. <el-button class="change-quit" type="text" style="color: #F56C6C;padding: 0 5px" icon="el-icon-error" circle @click="cancelEdit('sort')"></el-button>
  71. <el-button class="change-success" type="text" style="margin-left: 0;color: #67C23A;padding: 0 5px" icon="el-icon-success" circle @click="handle('sort',scope.row)">
  72. </el-button>
  73. </div>
  74. </template>
  75. </el-table-column> -->
  76. <el-table-column label="商品名称" min-width="200" prop="goods_name" align="center">
  77. <template slot-scope="scope">
  78. <div flex="cross:center">
  79. <div style="margin-right: 10px;">
  80. <el-image style="width: 50px; height: 50px;border-radius: 5px;" :src="scope.row.cover_pic"></el-image>
  81. </div>
  82. <div v-if="goods_name_id != scope.row.id">
  83. <el-tooltip class="item" effect="dark" content="商品名称" placement="top">
  84. <span>{{scope.row.goods_name}}</span>
  85. </el-tooltip>
  86. <el-button class="edit-sort" type="text" @click="edit(scope.row,'goods_name')">
  87. <img src="resources/img/mall/order/edit.png" alt="">
  88. </el-button>
  89. </div>
  90. <div style="display: flex;align-items: center" v-else>
  91. <el-input style="min-width: 70px" size="mini" class="change" v-model="goods_name" autocomplete="off"></el-input>
  92. <el-button class="change-quit" type="text" style="color: #F56C6C;padding: 0 5px" icon="el-icon-error" circle @click="cancelEdit('goods_name')"></el-button>
  93. <el-button class="change-success" type="text" style="margin-left: 0;color: #67C23A;padding: 0 5px" icon="el-icon-success" circle @click="handle('goods_name',scope.row)">
  94. </el-button>
  95. </div>
  96. </div>
  97. </template>
  98. </el-table-column>
  99. <el-table-column label="分类" align="center">
  100. <template slot-scope="scope">
  101. <div class="goods-cat">
  102. <el-tag v-if="scope.row.cats && scope.row.cats.length > 0" size="mini">
  103. {{scope.row.cats[0].name}}
  104. </el-tag>
  105. <el-tooltip v-if="scope.row.cats && scope.row.cats.length > 1" placement="top">
  106. <div slot="content">
  107. <span v-for="item in scope.row.cats" :key="item.id">{{item.name}}&nbsp;</span>
  108. </div>
  109. <span>...</span>
  110. </el-tooltip>
  111. </div>
  112. </template>
  113. </el-table-column>
  114. <el-table-column label="售价" prop="price" align="center" sortable="false">
  115. <template slot-scope="scope">
  116. <div size="small">{{scope.row.price}}</div>
  117. </template>
  118. </el-table-column>
  119. <el-table-column label="商品标签" prop="label_name" align="center">
  120. <template slot-scope="scope">
  121. <div size="small">{{scope.row.label_name}}</div>
  122. </template>
  123. </el-table-column>
  124. <el-table-column label="小店收益" prop="store_scale" align="center" min-width="100">
  125. <template slot-scope="scope">
  126. <div size="small">{{scope.row.store_scale}}%</div>
  127. </template>
  128. </el-table-column>
  129. <el-table-column label="最低提货数量" prop="min_num" align="center"
  130. min-width="120">
  131. <template slot-scope="scope">
  132. <div size="small">{{scope.row.min_num}}</div>
  133. </template>
  134. </el-table-column>
  135. <el-table-column label="临期提醒" prop="warn_day" align="center" min-width="100">
  136. <template slot-scope="scope">
  137. <div size="small">{{scope.row.warn_day}}</div>
  138. </template>
  139. </el-table-column>
  140. <el-table-column label="状态" prop="is_on_sale" align="center">
  141. <template slot-scope="scope">
  142. <el-switch
  143. v-model="scope.row.is_on_sale"
  144. :active-value="1"
  145. :inactive-value="0"
  146. @change="handle('is_on_sale', scope.row)"
  147. >
  148. </el-switch>
  149. </template>
  150. </el-table-column>
  151. <el-table-column label="来源" prop="goods_source" align="center">
  152. <template slot-scope="scope">
  153. <el-tag size="mini" :type="scope.row.goods_source == '' ? 'success' : 'danger'">
  154. {{scope.row.goods_source == '' ? '自营' : '供应链'}}
  155. </el-tag>
  156. </template>
  157. </el-table-column>
  158. <el-table-column label="创建时间" width="160" prop="created_at" align="center">
  159. <template slot-scope="scope">
  160. <div size="small">{{scope.row.created_at|dateTimeFormat('Y-m-d H:i:s')}}</div>
  161. </template>
  162. </el-table-column>
  163. <el-table-column label="操作" min-width="300" align="center">
  164. <template slot-scope="scope">
  165. <template>
  166. <el-button type="text" @click="handle('edit',scope.row)">编辑</el-button>
  167. <el-button type="text" @click="handle('delete',scope.row)">删除</el-button>
  168. </template>
  169. </template>
  170. </el-table-column>
  171. </el-table>
  172. <div style="text-align: right;margin: 20px 0;">
  173. <el-pagination @current-change="pagination" background layout="prev, pager, next" :page-count="pageCount"></el-pagination>
  174. </div>
  175. </el-tab-pane>
  176. </el-tabs>
  177. </div>
  178. <el-dialog title="编辑商品" width="300px" :visible.sync="goodsEditVisible" append-to-body >
  179. <el-form :inline="true" size="small" label-width="200px">
  180. <el-form-item label="小店收益">
  181. <el-input v-model="goodsEdit.store_scale" placeholder="小店收益"></el-input>
  182. </el-form-item>
  183. <el-form-item label="配送方式">
  184. <el-checkbox-group v-model="goodsEdit.freight_type">
  185. <el-checkbox key="1" :label="1">快递物流</el-checkbox>
  186. <el-checkbox key="3" :label="3">同城配送</el-checkbox>
  187. <el-checkbox key="2" :label="2">上门自提</el-checkbox>
  188. </el-checkbox-group>
  189. </el-form-item>
  190. <el-form-item label="最低提货数量">
  191. <el-input v-model="goodsEdit.min_num" placeholder="最低提货数量"></el-input>
  192. </el-form-item>
  193. <el-form-item label="临期提醒">
  194. <el-input v-model="goodsEdit.warn_day" placeholder="临期提醒"></el-input>
  195. </el-form-item>
  196. </el-form>
  197. <span slot="footer" class="dialog-footer">
  198. <el-button @click="goodsEditVisible = false" type="default" size="small">取消</el-button>
  199. <el-button type="primary" :loading="btnLoading" style="margin-bottom: 10px;" size="small"
  200. @click="handle('save',goodsEdit)">保存</el-button>
  201. </span>
  202. </el-dialog>
  203. </el-card>
  204. <!-- 分类筛选 -->
  205. <com-add-cat ref="cats" :new-cats="search_data.cats" @select="selectCat" :mch_id="mch_id"></com-add-cat>
  206. <!-- 绑定跳转链接 -->
  207. <!-- <pay-success-select-jump-url addons="Happiness" :goods="currentItem" :show="paySuccessSelectJumpUrlDialogVisible"-->
  208. <!-- @hide="hidePaySuccessSelectJumpUrlDialogVisible"></pay-success-select-jump-url>-->
  209. </div>
  210. <script>
  211. const app = new Vue({
  212. el: '#app',
  213. data() {
  214. return {
  215. goods_name: '',
  216. goods_id: '',
  217. tabs: [
  218. {
  219. name: '全部商品',
  220. id: '0',
  221. },
  222. ],
  223. activeName: '0',
  224. list: [],
  225. listLoading: false,
  226. page: 1,
  227. pageCount: 0,
  228. mch_id: 0, // 这个地方不知道要怎么获取
  229. searchCats: [],
  230. datetime: [],
  231. search_data: { // 筛选条件
  232. type: '',
  233. cats: [],
  234. start: null,
  235. end: null,
  236. goods_id: null,
  237. goods_name: null,
  238. goods_type: null,
  239. },
  240. sort: 0,
  241. sort_id: 0,
  242. goods_name_id: 0,
  243. export_url: 'mall/goods/export-excel',
  244. export_list: {},
  245. group_buy_active_arr: {},
  246. selectedGoodIds: [],
  247. pay_success_jump: 0,
  248. paySuccessSelectJumpUrlDialogVisible: false,
  249. currentItem: {},
  250. goodsLabel:[],
  251. btnLoading:false,
  252. goodsEditVisible:false,
  253. goodsEdit: {},
  254. freight_type: [1,2,3],
  255. };
  256. },
  257. mounted: function() {
  258. this.getList();
  259. },
  260. computed: {
  261. show_clear_search_btn: function() {
  262. return !isEmpty(this.search_data.cats) || !isEmpty(this.search_data.start) ||
  263. !isEmpty(this.search_data.end) || !isEmpty(this.search_data.goods_id) ||
  264. !isEmpty(this.search_data.goods_name);
  265. }
  266. },
  267. methods: {
  268. selectCat(arr) {
  269. this.search_data.cats = [];
  270. arr.forEach(it => this.search_data.cats.push(it.id))
  271. this.getList()
  272. },
  273. clearCat() { // 清除分类
  274. this.search_data.cats = []
  275. this.getList()
  276. },
  277. changeTime(e) {
  278. // console.log(e)
  279. this.search_data.start = e[0]
  280. this.search_data.end = e[1]
  281. },
  282. handleClick(res) { //标签页切换
  283. if (this.search_data.status == this.activeName) return;
  284. this.search_data.type = this.activeName;
  285. this.getList();
  286. },
  287. sortChange(row) {
  288. if (row.prop) {
  289. this.search_data.sort_field = row.prop;
  290. this.search_data.sort_type = row.order == "descending" ? 'desc' : 'asc';
  291. } else {
  292. this.search_data.sort_prop = null;
  293. this.search_data.sort_type = null;
  294. }
  295. this.getList();
  296. },
  297. search() {
  298. this.page = 1;
  299. this.getList();
  300. },
  301. clearSearch() {
  302. this.search_data.cats = [];
  303. this.search_data.start = null;
  304. this.search_data.end = null;
  305. this.search_data.goods_id = null;
  306. this.search_data.goods_name = null;
  307. this.datetime = [];
  308. this.getList();
  309. },
  310. handle(type, data = null) {
  311. let id = data ? parseInt(data.id) : '';
  312. let params = {
  313. r: 'happiness/store-goods/edit'
  314. };
  315. switch (type) {
  316. case 'edit':
  317. if (id) params = Object.assign(params, {
  318. id: id
  319. });
  320. this.goodsEdit={
  321. id: id,
  322. store_scale: data.store_scale,
  323. min_num: data.min_num,
  324. warn_day:data.warn_day,
  325. freight_type:data.freight_type,
  326. }
  327. this.goodsEditVisible=true
  328. break;
  329. case 'save':
  330. params=this.goodsEdit
  331. params.r='happiness/store-goods/edit'
  332. this.btnLoading=true
  333. this.send(params)
  334. break;
  335. case 'add':
  336. params.r='happiness/store-goods/add'
  337. navigateTo(params);
  338. break;
  339. case 'delete':
  340. if (id) params = Object.assign(params, {
  341. id: id
  342. });
  343. params.r= 'happiness/store-goods/del-goods'
  344. this.delete( params)
  345. break;
  346. case 'is_on_sale':
  347. let param = {
  348. id: id,
  349. is_on_sale: data.is_on_sale,
  350. type,
  351. r: 'happiness/store-goods/index'
  352. };
  353. const operate_type = data.is_on_sale == 0 ? '下架' : '上架';
  354. this.$confirm('是否' + operate_type + '该商品?', '警告', {
  355. type: 'warning'
  356. }).then(() => {
  357. this.send(param)
  358. }).catch(() => {
  359. this.getList();
  360. });
  361. break;
  362. }
  363. this.cancelEdit(type);
  364. },
  365. deepClone(obj) {
  366. var o, i, j, k;
  367. if (typeof(obj) != "object" || obj === null) return obj;
  368. if (obj instanceof(Array)) {
  369. o = [];
  370. i = 0;
  371. j = obj.length;
  372. for (; i < j; i++) {
  373. if (typeof(obj[i]) == "object" && obj[i] != null) {
  374. o[i] = arguments.callee(obj[i]);
  375. } else {
  376. o[i] = obj[i];
  377. }
  378. }
  379. } else {
  380. o = {};
  381. for (i in obj) {
  382. if (typeof(obj[i]) == "object" && obj[i] != null) {
  383. o[i] = arguments.callee(obj[i]);
  384. } else {
  385. o[i] = obj[i];
  386. }
  387. }
  388. }
  389. return o;
  390. },
  391. delete(param) {
  392. this.$confirm('确定删除该商品, 是否继续?', '提示', {
  393. confirmButtonText: '确定',
  394. cancelButtonText: '取消',
  395. type: 'warning'
  396. }).then(() => {
  397. this.send(param)
  398. }).catch(() => {
  399. this.getList();
  400. });
  401. },
  402. send(params) {
  403. let self = this;
  404. request({
  405. params: {
  406. r: params.r
  407. },
  408. method: 'post',
  409. data: params
  410. }).then(e => {
  411. if (e.data.code == 0) {
  412. self.$message.success(e.data.msg);
  413. self.getList();
  414. self.goodsEditVisible=false
  415. self.btnLoading=false
  416. } else {
  417. self.$message.error(e.data.msg);
  418. }
  419. }).catch(e => {
  420. console.log(e);
  421. });
  422. },
  423. edit(row, type) {
  424. switch (type) {
  425. case 'sort':
  426. this.sort = row.sort;
  427. this.sort_id = row.id;
  428. break;
  429. case 'goods_name':
  430. this.goods_name_id = row.id;
  431. this.goods_name = row.goods_name;
  432. break;
  433. }
  434. },
  435. cancelEdit(type) {
  436. switch (type) {
  437. case 'sort':
  438. this.sort = 0;
  439. this.sort_id = 0;
  440. break;
  441. case 'goods_name':
  442. this.goods_name = '';
  443. this.goods_name_id = 0;
  444. break;
  445. }
  446. },
  447. searchClick() {
  448. this.page = 1;
  449. this.getList();
  450. },
  451. pagination(currentPage) {
  452. let self = this;
  453. self.page = currentPage;
  454. self.getList();
  455. },
  456. // 获取商品列表
  457. getList() {
  458. let self = this;
  459. let basic_params = {
  460. r: 'happiness/store-goods/index',
  461. page: self.page,
  462. };
  463. params = Object.assign(basic_params, this.search_data);
  464. if (self.listLoading == false) {
  465. self.listLoading = true;
  466. request({
  467. params: params,
  468. method: 'get',
  469. }).then(e => {
  470. self.listLoading = false;
  471. if (e.data.code == 0) {
  472. self.list = e.data.data.list;
  473. self.goodsLabel= e.data.data.goods_label;
  474. if(e.data.data.goods_label)
  475. {
  476. console.log(e.data.data.goods_label);
  477. if(self.tabs.length==1)
  478. {
  479. self.tabs=self.tabs.concat(self.goodsLabel)
  480. }
  481. }
  482. self.group_buy_active_arr = e.data.data.group_buy_active_arr;
  483. self.pageCount = e.data.data.page_count;
  484. this.export_list = e.data.data.export_list;
  485. this.pay_success_jump = e.data.data.pay_success_jump
  486. } else {
  487. self.$message.error(e.data.msg);
  488. }
  489. }).catch(e => {
  490. self.$message.error(e.data.msg);
  491. self.listLoading = false;
  492. });
  493. }
  494. },
  495. // 批量下架选中
  496. handleSelectionChange(val) {
  497. // console.log(val, 'handleSelectionChange ============= ');
  498. if (val.length) {
  499. this.selectedGoodIds = val.map((e) => {
  500. if (e.can_change_status == true) {
  501. return e.id;
  502. }
  503. });
  504. // console.log(this.selectedGoodIds, 'this.selectedGoodIds =============== ');
  505. } else {
  506. this.selectedGoodIds = [];
  507. }
  508. },
  509. // 批量下架商品
  510. multipleOff() {
  511. let self = this;
  512. if (!self.selectedGoodIds.length) {
  513. self.$message.error('请先选择要下架的商品');
  514. return false;
  515. }
  516. self.listLoading = true;
  517. self.$confirm('是否确认下架所选中商品', '警告', {
  518. confirmButtonText: '确定',
  519. cancelButtonText: '取消',
  520. type: 'warning'
  521. }).then(() => {
  522. request({
  523. params: {
  524. r: 'happiness/store-goods/mutiple-off',
  525. },
  526. method: 'post',
  527. data: {
  528. type: 1,
  529. good_ids: self.selectedGoodIds,
  530. }
  531. }).then(e => {
  532. self.listLoading = false;
  533. if (e.data.code == 0) {
  534. self.$message.success('操作成功');
  535. self.getList();
  536. } else {
  537. self.$message.error(e.data.msg);
  538. return false;
  539. }
  540. }).catch(e => {
  541. self.listLoading = false;
  542. console.log(e);
  543. self.$message.error('网络错误');
  544. return false;
  545. });
  546. }).catch(() => {
  547. self.listLoading = false;
  548. console.log('已取消操作');
  549. return false;
  550. });
  551. },
  552. // 批量上架商品
  553. multipleOn() {
  554. let self = this;
  555. if (!self.selectedGoodIds.length) {
  556. self.$message.error('请先选择要上架的商品');
  557. return false;
  558. }
  559. self.listLoading = true;
  560. self.$confirm('是否确认上架所选中商品', '警告', {
  561. confirmButtonText: '确定',
  562. cancelButtonText: '取消',
  563. type: 'warning'
  564. }).then(() => {
  565. request({
  566. params: {
  567. r: 'happiness/store-goods/mutiple-off',
  568. },
  569. method: 'post',
  570. data: {
  571. type: 2,
  572. good_ids: self.selectedGoodIds,
  573. }
  574. }).then(e => {
  575. self.listLoading = false;
  576. if (e.data.code == 0) {
  577. self.$message.success('操作成功');
  578. self.getList();
  579. } else {
  580. self.$message.error(e.data.msg);
  581. return false;
  582. }
  583. }).catch(e => {
  584. self.listLoading = false;
  585. console.log(e);
  586. self.$message.error('网络错误');
  587. return false;
  588. });
  589. }).catch(() => {
  590. self.listLoading = false;
  591. console.log('已取消操作');
  592. return false;
  593. });
  594. },
  595. hidePaySuccessSelectJumpUrlDialogVisible() {
  596. this.paySuccessSelectJumpUrlDialogVisible = false
  597. },
  598. onChangeJumpUrl(goods) {
  599. this.currentItem = goods
  600. this.paySuccessSelectJumpUrlDialogVisible = true
  601. },
  602. checkSelectable(row) {
  603. if (row.can_change_status == true) {
  604. return true;
  605. } else {
  606. return false;
  607. }
  608. },
  609. }
  610. });
  611. </script>