index.vue 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226
  1. <template>
  2. <div class="divBox relative">
  3. <el-card
  4. v-if="checkPermi(['merchant:product:page:list'])"
  5. :bordered="false"
  6. shadow="never"
  7. class="ivu-mt"
  8. :body-style="{ padding: 0 }"
  9. >
  10. <div class="padding-add">
  11. <el-form inline size="small" label-position="right" @submit.native.prevent>
  12. <el-form-item label="商品搜索:">
  13. <el-input
  14. v-model.trim="keywords"
  15. placeholder="请输入商品名称关键字"
  16. class="form_content_width"
  17. size="small"
  18. @keyup.enter.native="handleSeachList"
  19. clearable
  20. ></el-input>
  21. </el-form-item>
  22. <el-form-item label="平台分类:">
  23. <el-cascader
  24. v-model="tableFrom.categoryId"
  25. :options="merPlatProductClassify"
  26. :props="propsPlant"
  27. clearable
  28. class="form_content_width"
  29. @change="handleSeachList"
  30. size="small"
  31. placeholder="请输入平台商品分类"
  32. />
  33. </el-form-item>
  34. <el-form-item label="商户分类:">
  35. <el-cascader
  36. v-model="tableFrom.cateId"
  37. :options="merProductClassify"
  38. :props="propsMer"
  39. clearable
  40. class="form_content_width"
  41. @change="handleSeachList"
  42. size="small"
  43. placeholder="请输入商户商品分类"
  44. />
  45. </el-form-item>
  46. <el-form-item label="会员商品:">
  47. <el-select
  48. v-model="tableFrom.isPaidMember"
  49. clearable
  50. size="small"
  51. placeholder="请选择"
  52. class="selWidth"
  53. @change="handleSeachList"
  54. >
  55. <el-option label="是" value="true" />
  56. <el-option label="否" value="false" />
  57. </el-select>
  58. </el-form-item>
  59. <el-form-item label="商品类型:">
  60. <el-select
  61. v-model="tableFrom.productType"
  62. clearable
  63. size="small"
  64. placeholder="请选择"
  65. class="selWidth"
  66. @change="handleSeachList"
  67. >
  68. <el-option
  69. v-for="(item, index) in productTypeList"
  70. :label="item.label"
  71. :value="item.value"
  72. :key="index"
  73. />
  74. </el-select>
  75. </el-form-item>
  76. <el-form-item>
  77. <el-button type="primary" size="small" @click="handleSeachList">查询</el-button>
  78. <el-button size="small" @click="handleReset">重置</el-button>
  79. </el-form-item>
  80. </el-form>
  81. </div>
  82. </el-card>
  83. <el-card class="box-card mt14" :body-style="{ padding: '0 20px 20px' }" shadow="never" :bordered="false">
  84. <div class="clearfix" ref="headerBox" v-if="checkPermi(['merchant:product:page:list'])">
  85. <el-tabs class="list-tabs mb5" v-model="tableFrom.type" @tab-click="handleSeachList">
  86. <el-tab-pane
  87. :label="item.name + '(' + item.count + ')'"
  88. :name="item.type.toString()"
  89. v-for="(item, index) in headeNum"
  90. :key="index"
  91. />
  92. </el-tabs>
  93. </div>
  94. <el-button size="small" type="primary" v-hasPermi="['merchant:product:save']" @click="handleAdd('isAdd')"
  95. >添加商品</el-button
  96. >
  97. <el-button
  98. class="mr14"
  99. @click="handleAdd('isCopy')"
  100. size="small"
  101. type="success"
  102. v-hasPermi="['merchant:product:import:product']"
  103. >商品采集</el-button
  104. >
  105. <el-dropdown size="small">
  106. <el-button :class="checkedIds.length > 0 ? '' : 'active'" :disabled="checkedIds.length > 0 ? false : true">
  107. 批量设置<i class="el-icon-arrow-down el-icon--right"></i>
  108. </el-button>
  109. <el-dropdown-menu slot="dropdown">
  110. <template v-if="checkedIds.length > 0 ? true : false">
  111. <el-dropdown-item
  112. v-if="
  113. tableFrom.type == ProductTypeEnum.InTheWarehouse &&
  114. checkPermi(['merchant:product:batch:set:freight:template'])
  115. "
  116. @click.native="handleSetFreight()"
  117. >设置运费</el-dropdown-item
  118. >
  119. <el-dropdown-item
  120. v-if="
  121. tableFrom.type == ProductTypeEnum.InTheWarehouse && checkPermi(['merchant:product:batch:set:brokerage'])
  122. "
  123. @click.native="handleSetCommission()"
  124. >设置佣金</el-dropdown-item
  125. >
  126. <el-dropdown-item
  127. v-if="
  128. checkPermi(['merchant:product:batch:down']) &&
  129. (tableFrom.type == ProductTypeEnum.OnSale || SoldOutAndAlertInventory)
  130. "
  131. @click.native="batchDelisting('down')"
  132. >批量下架</el-dropdown-item
  133. >
  134. <el-dropdown-item
  135. v-if="
  136. checkPermi(['merchant:product:batch:up']) &&
  137. (tableFrom.type == ProductTypeEnum.InTheWarehouse || SoldOutAndAlertInventory)
  138. "
  139. @click.native="batchDelisting('up')"
  140. >批量上架</el-dropdown-item
  141. >
  142. <el-dropdown-item
  143. v-if="checkPermi(['merchant:product:batch:restore']) && tableFrom.type == ProductTypeEnum.RecycleBin"
  144. @click.native="handleRestore()"
  145. >批量恢复</el-dropdown-item
  146. >
  147. <el-dropdown-item
  148. v-if="checkPermi(['merchant:product:batch:delete']) && tableFrom.type == ProductTypeEnum.RecycleBin"
  149. @click.native="handleRecycleBin(tableFrom.type)"
  150. >批量删除</el-dropdown-item
  151. >
  152. <el-dropdown-item
  153. v-if="
  154. tableFrom.type === ProductTypeEnum.PendingReview && checkPermi(['merchant:product:batch:submit:audit'])
  155. "
  156. @click.native="handlePendingReview()"
  157. >提交审核</el-dropdown-item
  158. >
  159. <el-dropdown-item
  160. v-if="
  161. tableFrom.type == ProductTypeEnum.InTheWarehouse &&
  162. checkPermi(['merchant:product:batch:add:feedback:coupons'])
  163. "
  164. @click.native="handleAddCoupon()"
  165. >添加回馈券</el-dropdown-item
  166. >
  167. <el-dropdown-item
  168. v-if="checkPermi(['merchant:product:batch:recycle']) && RecycleBin"
  169. @click.native="handleRecycleBin(tableFrom.type)"
  170. >加入回收站</el-dropdown-item
  171. >
  172. </template>
  173. </el-dropdown-menu>
  174. </el-dropdown>
  175. <el-table
  176. v-loading="listLoading"
  177. :data="tableData.data"
  178. style="width: 100%"
  179. size="small"
  180. class="mt20"
  181. :highlight-current-row="true"
  182. highlight-current-row
  183. @selection-change="handleSelectionChange"
  184. @select-all="selectAll"
  185. @select="selectOne"
  186. >
  187. <el-table-column type="expand" width="40">
  188. <template slot-scope="props">
  189. <el-form label-position="left" inline class="demo-table-expand">
  190. <el-form-item label="收藏:">
  191. <span>{{ props.row.collectCount }}</span>
  192. </el-form-item>
  193. <el-form-item label="初始销量:">
  194. <span>{{ props.row.ficti }}</span>
  195. </el-form-item>
  196. <el-form-item label="拒绝原因:" v-if="tableFrom.type == 7">
  197. <span>{{ props.row.reason }}</span>
  198. </el-form-item>
  199. </el-form>
  200. </template>
  201. </el-table-column>
  202. <el-table-column type="selection" width="55"> </el-table-column>
  203. <el-table-column prop="id" label="ID" min-width="50" v-if="checkedCities.includes('ID')" />
  204. <el-table-column label="商品图" min-width="80" v-if="checkedCities.includes('商品图')">
  205. <template slot-scope="scope">
  206. <div class="demo-image__preview line-heightOne">
  207. <el-image :src="scope.row.image" :preview-src-list="[scope.row.image]" />
  208. </div>
  209. </template>
  210. </el-table-column>
  211. <el-table-column
  212. prop="name"
  213. label="商品名称"
  214. min-width="200"
  215. v-if="checkedCities.includes('商品名称')"
  216. :show-overflow-tooltip="true"
  217. >
  218. <template slot-scope="scope">
  219. <div>
  220. <span class="tags_name" :class="'name' + scope.row.specType">{{
  221. scope.row.specType ? '[多规格]' : '[单规格]'
  222. }}</span
  223. >{{ scope.row.name || '-' }}
  224. </div>
  225. </template>
  226. </el-table-column>
  227. <el-table-column prop="price" label="商品售价" min-width="90" v-if="checkedCities.includes('商品售价')" />
  228. <el-table-column prop="sales" label="销量" min-width="90" v-if="checkedCities.includes('销量')" />
  229. <el-table-column prop="stock" label="库存" min-width="90" v-if="checkedCities.includes('库存')" />
  230. <el-table-column label="失败原因" min-width="150" v-if="tableFrom.type === '7'" :show-overflow-tooltip="true">
  231. <template slot-scope="scope">
  232. <span class="textE93323">{{ scope.row.reason }}</span>
  233. </template>
  234. </el-table-column>
  235. <el-table-column label="状态" min-width="80" fixed="right" v-if="checkedCities.includes('状态')">
  236. <template slot-scope="scope">
  237. <el-switch
  238. v-if="checkPermi(['merchant:product:up', 'merchant:product:down'])"
  239. :disabled="IsShow"
  240. v-model="scope.row.isShow"
  241. :active-value="true"
  242. :inactive-value="false"
  243. active-text="上架"
  244. inactive-text="下架"
  245. @change="onchangeIsShow(scope.row)"
  246. />
  247. <div v-else>{{ scope.row.isShow ? '上架' : '下架' }}</div>
  248. </template>
  249. </el-table-column>
  250. <el-table-column width="190" fixed="right">
  251. <template slot="header">
  252. <p>
  253. <span style="padding-right: 5px">操作</span>
  254. <i class="el-icon-setting" @click="handleAddItem"></i>
  255. </p>
  256. </template>
  257. <template slot-scope="scope">
  258. <!--id:商品id,isDisabled:是否能编辑(1不能,2能),isCopy:是否是采集商品(1是,2不是)-->
  259. <template
  260. v-if="
  261. tableFrom.type !== ProductTypeEnum.InTheWarehouse &&
  262. tableFrom.type !== ProductTypeEnum.AlertInventory &&
  263. tableFrom.type !== ProductTypeEnum.PendingReview &&
  264. checkPermi(['merchant:product:info'])
  265. "
  266. >
  267. <router-link :to="{ path: `/product/list/creatProduct/${scope.row.id}/1/2/${scope.row.type}` }">
  268. 详情
  269. </router-link>
  270. </template>
  271. <template
  272. v-if="checkPermi(['merchant:product:submit:audit']) && tableFrom.type === ProductTypeEnum.PendingReview"
  273. >
  274. <a @click="handlePendingReview(scope.row)">提交审核</a>
  275. </template>
  276. <template
  277. v-if="tableFrom.type !== '5' && tableFrom.type !== '6' && checkPermi(['merchant:product:update'])"
  278. >
  279. <el-divider v-if="tableFrom.type !== '2' && tableFrom.type !== '4'" direction="vertical"></el-divider>
  280. <a @click="onEdit(scope.row)">编辑</a>
  281. </template>
  282. <template v-if="tableFrom.type === '5' && checkPermi(['merchant:product:restor'])">
  283. <el-divider direction="vertical"></el-divider>
  284. <a @click="handleRestore(scope.row, scope.$index)">恢复商品</a>
  285. </template>
  286. <template
  287. v-if="
  288. (tableFrom.type === ProductTypeEnum.OnSale ||
  289. (tableFrom.type === ProductTypeEnum.AlertInventory && scope.row.isShow) ||
  290. (tableFrom.type === ProductTypeEnum.SoldOut && scope.row.isShow)) &&
  291. checkPermi(['merchant:product:quick:stock:add'])
  292. "
  293. >
  294. <el-divider direction="vertical"></el-divider>
  295. <a @click="handleEdit(scope.row, true)">编辑库存</a>
  296. </template>
  297. <template
  298. v-if="
  299. (tableFrom.type === ProductTypeEnum.InTheWarehouse ||
  300. (tableFrom.type === ProductTypeEnum.SoldOut && !scope.row.isShow) ||
  301. (tableFrom.type === ProductTypeEnum.AlertInventory && !scope.row.isShow)) &&
  302. checkPermi(['merchant:product:review:free:edit'])
  303. "
  304. >
  305. <el-divider direction="vertical"></el-divider>
  306. <a @click="handleEdit(scope.row, false)">免审编辑</a>
  307. </template>
  308. <template
  309. v-if="
  310. (tableFrom.type === ProductTypeEnum.Audit ||
  311. tableFrom.type === ProductTypeEnum.ReviewFailed ||
  312. tableFrom.type === ProductTypeEnum.RecycleBin) &&
  313. checkPermi(['merchant:product:delete'])
  314. "
  315. >
  316. <el-divider direction="vertical"></el-divider>
  317. <a @click="handleDelete(scope.row.id, tableFrom.type)">{{
  318. tableFrom.type === '5' ? '删除' : '加入回收站'
  319. }}</a>
  320. </template>
  321. <!-- 待提审-->
  322. <template v-if="tableFrom.type === ProductTypeEnum.PendingReview">
  323. <el-divider direction="vertical"></el-divider>
  324. <el-dropdown size="small" trigger="click">
  325. <span class="el-dropdown-link"> 更多<i class="el-icon-arrow-down el-icon--right" /> </span>
  326. <el-dropdown-menu slot="dropdown">
  327. <el-dropdown-item
  328. class="infoItem"
  329. @click.native="handleInfo(scope.row.id, scope.row.type)"
  330. v-if="checkPermi(['merchant:product:info'])"
  331. >详情
  332. </el-dropdown-item>
  333. <el-dropdown-item
  334. v-if="checkPermi(['merchant:product:delete'])"
  335. @click.native="handleDelete(scope.row.id, tableFrom.type)"
  336. >{{ tableFrom.type === '5' ? '删除' : '加入回收站' }}</el-dropdown-item
  337. >
  338. </el-dropdown-menu>
  339. </el-dropdown>
  340. </template>
  341. <template
  342. v-if="
  343. tableFrom.type === ProductTypeEnum.InTheWarehouse ||
  344. tableFrom.type === ProductTypeEnum.AlertInventory ||
  345. (operation && !scope.row.isShow)
  346. "
  347. >
  348. <el-divider direction="vertical"></el-divider>
  349. <el-dropdown size="small" trigger="click">
  350. <span class="el-dropdown-link"> 更多<i class="el-icon-arrow-down el-icon--right" /> </span>
  351. <el-dropdown-menu slot="dropdown">
  352. <el-dropdown-item
  353. class="infoItem"
  354. @click.native="handleInfo(scope.row.id, scope.row.type)"
  355. v-if="(tableFrom.type === '2' || tableFrom.type === '4') && checkPermi(['merchant:product:info'])"
  356. >详情
  357. </el-dropdown-item>
  358. <el-dropdown-item
  359. @click.native="handleSetFreight(scope.row)"
  360. v-if="
  361. checkPermi(['merchant:product:set:freight:template']) &&
  362. scope.row.type !== 5 &&
  363. scope.row.type !== 6
  364. "
  365. >设置运费</el-dropdown-item
  366. >
  367. <el-dropdown-item
  368. v-if="checkPermi(['merchant:product:set:brokerage'])"
  369. @click.native="handleSetCommission(scope.row)"
  370. >设置佣金</el-dropdown-item
  371. >
  372. <el-dropdown-item
  373. v-if="checkPermi(['merchant:product:add:feedback:coupons'])"
  374. @click.native="handleAddCoupon(scope.row)"
  375. >添加回馈券</el-dropdown-item
  376. >
  377. <el-dropdown-item
  378. v-if="checkPermi(['merchant:product:delete'])"
  379. @click.native="handleDelete(scope.row.id, tableFrom.type)"
  380. >{{ tableFrom.type === '5' ? '删除' : '加入回收站' }}</el-dropdown-item
  381. >
  382. </el-dropdown-menu>
  383. </el-dropdown>
  384. </template>
  385. </template>
  386. </el-table-column>
  387. </el-table>
  388. <div class="block">
  389. <el-pagination
  390. background
  391. :page-sizes="$constants.page.limit"
  392. :page-size="tableFrom.limit"
  393. :current-page="tableFrom.page"
  394. layout="total, sizes, prev, pager, next, jumper"
  395. :total="tableData.total"
  396. @size-change="handleSizeChange"
  397. @current-change="pageChange"
  398. />
  399. </div>
  400. <div class="card_abs" v-show="card_select_show">
  401. <template>
  402. <div class="cell_ht">
  403. <el-checkbox :indeterminate="isIndeterminate" v-model="checkAll" @change="handleCheckAllChange"
  404. >全选</el-checkbox
  405. >
  406. <el-button type="text" @click="checkSave()">保存</el-button>
  407. </div>
  408. <el-checkbox-group v-model="checkedCities" @change="handleCheckedCitiesChange">
  409. <el-checkbox v-for="item in columnData" :label="item" :key="item" class="check_cell">{{
  410. item
  411. }}</el-checkbox>
  412. </el-checkbox-group>
  413. </template>
  414. </div>
  415. </el-card>
  416. <!--编辑库存-->
  417. <el-drawer
  418. :title="!stockEdit ? '免审编辑' : '编辑库存'"
  419. :visible.sync="drawer"
  420. :direction="direction"
  421. :size="1500"
  422. class="showHeader"
  423. :before-close="handleCloseEdit"
  424. >
  425. <store-edit
  426. :productId="productId"
  427. v-if="drawer && productId"
  428. :productType="productType"
  429. @subSuccess="subSuccess"
  430. :stockEdit="stockEdit"
  431. :isSub="isSub"
  432. ></store-edit>
  433. </el-drawer>
  434. <!-- 设置运费模板-->
  435. <el-dialog
  436. :visible.sync="dialogVisible"
  437. title="设置运费"
  438. destroy-on-close
  439. :close-on-click-modal="false"
  440. width="600px"
  441. class="dialog-top"
  442. >
  443. <el-form
  444. ref="formValidate"
  445. class="formValidate"
  446. :rules="ruleValidate"
  447. :model="formValidate"
  448. label-width="75px"
  449. @submit.native.prevent
  450. >
  451. <el-form-item label="运费模板:" prop="tempId">
  452. <el-select v-model="formValidate.tempId" placeholder="请选择" class="mr20" style="width: 100%">
  453. <el-option v-for="item in shippingTemplates" :key="item.id" :label="item.name" :value="item.id" />
  454. </el-select>
  455. </el-form-item>
  456. <el-form-item>
  457. <div class="dialog-footer-inner">
  458. <el-button class="btns" size="small" @click="handleClose">取消</el-button>
  459. <el-button
  460. type="primary"
  461. class="submission"
  462. @click="handleSubmit('formValidate')"
  463. :loading="loadingBtn"
  464. v-if="checkPermi(['merchant:product:update'])"
  465. >确定</el-button
  466. >
  467. </div>
  468. </el-form-item>
  469. </el-form>
  470. </el-dialog>
  471. <!--批量设置佣金弹窗-->
  472. <el-dialog v-if="dialogCommision" title="设置佣金" :visible.sync="dialogCommision" width="600px">
  473. <el-form ref="commisionForm" :model="commisionForm" :rules="commisionRule" @submit.native.prevent>
  474. <el-form-item label="一级佣金比例:" prop="extension_one">
  475. <el-input-number
  476. v-model="commisionForm.brokerage"
  477. :step="1"
  478. step-strictly
  479. :min="0"
  480. :max="100"
  481. class="priceBox"
  482. controls-position="right"
  483. />
  484. </el-form-item>
  485. <el-form-item label="二级佣金比例:" prop="extension_two">
  486. <el-input-number
  487. v-model="commisionForm.brokerageTwo"
  488. :step="1"
  489. :min="0"
  490. step-strictly
  491. :max="100"
  492. class="priceBox"
  493. controls-position="right"
  494. />
  495. </el-form-item>
  496. <el-form-item>
  497. <span>备注:订单交易成功后给推广员返佣的比例,例:一级佣金比例设置5,则返订单金额的5%</span>
  498. </el-form-item>
  499. </el-form>
  500. <span slot="footer" class="dialog-footer">
  501. <el-button @click="dialogCommision = false">取消</el-button>
  502. <el-button type="primary" @click="submitCommisionForm('commisionForm')">提交</el-button>
  503. </span>
  504. </el-dialog>
  505. <!-- 选择商品类型弹窗-->
  506. <!--product-tpye ref="productTpye" :addType="addType"></product-tpye-->
  507. </div>
  508. </template>
  509. <script>
  510. // +----------------------------------------------------------------------
  511. // | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
  512. // +----------------------------------------------------------------------
  513. // | Copyright (c) 2016~2025 https://www.crmeb.com All rights reserved.
  514. // +----------------------------------------------------------------------
  515. // | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
  516. // +----------------------------------------------------------------------
  517. // | Author: CRMEB Team <admin@crmeb.com>
  518. // +----------------------------------------------------------------------
  519. import {
  520. productLstApi,
  521. productDeleteApi,
  522. putOnShellApi,
  523. offShellApi,
  524. productHeadersApi,
  525. restoreApi,
  526. productExcelApi,
  527. productAuditApi,
  528. productBatchDownApi,
  529. productBatchUpApi,
  530. productSetFreightApi,
  531. productBatchFreightApi,
  532. productBrokerageApi,
  533. productBatchBrokerageApi,
  534. productBatchAddCouponsApi,
  535. productAddCouponsApi,
  536. productBatchDeleteApi,
  537. productBatchRecycleApi,
  538. productBatchRestoreApi,
  539. productBatchAuditApi,
  540. } from '@/api/product';
  541. import { getToken } from '@/utils/auth';
  542. import { checkPermi } from '@/utils/permission'; // 权限判断函数
  543. import { mapGetters } from 'vuex';
  544. //import storeEdit from './components/storeEdit';
  545. //import productTpye from './components/productTpye.vue';
  546. //import { ProductTypeEnum } from '@/enums/productEnums';
  547. import * as $constants from '@/utils/constants';
  548. import { useProduct } from '@/hooks/use-product';
  549. import { handleDeleteTable } from '@/libs/public';
  550. const { productTypeList } = useProduct();
  551. const objTitle = ['出售中', '仓库中', '已售罄', '警戒库存', '回收站', '待审核', '审核失败', '待提审'];
  552. const tableFroms = {
  553. page: 1,
  554. limit: $constants.page.limit[0],
  555. cateId: '',
  556. keywords: '',
  557. type: '1',
  558. categoryId: null,
  559. isPaidMember: null,
  560. productType: null,
  561. };
  562. export default {
  563. name: 'ProductList',
  564. directives: {
  565. // 计算是否滚动到最下面
  566. selectLoadMore: {
  567. bind(el, binding) {
  568. // 获取element-ui定义好的scroll盒子
  569. const SELECTWRAP_DOM = el.querySelector('.el-select-dropdown .el-select-dropdown__wrap');
  570. SELECTWRAP_DOM.addEventListener('scroll', function () {
  571. if (this.scrollHeight - this.scrollTop < this.clientHeight + 1) {
  572. binding.value();
  573. }
  574. });
  575. },
  576. },
  577. },
  578. // components: { storeEdit, productTpye },
  579. data() {
  580. return {
  581. productTypeList: productTypeList, //商品类型
  582. drawer: false,
  583. direction: 'rtl',
  584. propsPlant: {
  585. children: 'childList',
  586. label: 'name',
  587. value: 'id',
  588. multiple: false,
  589. emitPath: false,
  590. },
  591. propsMer: {
  592. children: 'childList',
  593. label: 'name',
  594. value: 'id',
  595. multiple: false,
  596. emitPath: false,
  597. checkStrictly: true,
  598. },
  599. headeNum: [],
  600. listLoading: false,
  601. tableData: {
  602. data: [],
  603. total: 0,
  604. },
  605. tableFrom: Object.assign({}, tableFroms),
  606. keywords: '',
  607. categoryList: [],
  608. objectUrl: process.env.VUE_APP_BASE_API,
  609. card_select_show: false,
  610. checkAll: false,
  611. checkedCities: ['ID', '商品图', '商品名称', '商品售价', '销量', '库存', '状态'],
  612. columnData: ['ID', '商品图', '商品名称', '商品售价', '销量', '库存', '状态'],
  613. isIndeterminate: true,
  614. productId: 0,
  615. stockEdit: false,
  616. multipleSelectionAll: [],
  617. checkedIds: [], //选中的id
  618. ruleValidate: {
  619. tempId: [{ required: true, message: '请选择运费模板', trigger: 'change' }],
  620. },
  621. formValidate: {
  622. tempId: '',
  623. },
  624. loadingBtn: false,
  625. dialogVisible: false,
  626. dialogCommision: false, //佣金弹窗
  627. commisionForm: { brokerage: 0, brokerageTwo: 0, id: 0, idList: [] }, //设置佣金表单
  628. commisionRule: {
  629. brokerage: [{ required: true, message: '请输入一级佣金', trigger: 'change' }],
  630. brokerageTwo: [{ required: true, message: '请输入二级佣金', trigger: 'change' }],
  631. },
  632. keyNum: 0,
  633. couponIds: [], //优惠券集合
  634. productInfo: null, //商品详情
  635. productType: 0, //商品类型
  636. isSub: false, //佣金设置是否单独设置
  637. addType: 'isAdd',
  638. };
  639. },
  640. computed: {
  641. ProductTypeEnum() {
  642. return ProductTypeEnum;
  643. },
  644. //操作上下架禁用
  645. IsShow() {
  646. return (
  647. this.tableFrom.type == ProductTypeEnum.RecycleBin ||
  648. this.tableFrom.type == ProductTypeEnum.Audit ||
  649. this.tableFrom.type == ProductTypeEnum.ReviewFailed ||
  650. this.tableFrom.type == ProductTypeEnum.PendingReview
  651. );
  652. },
  653. //已售罄或者警戒库存
  654. SoldOutAndAlertInventory() {
  655. return (
  656. this.tableFrom.type == this.ProductTypeEnum.SoldOut ||
  657. this.tableFrom.type == this.ProductTypeEnum.AlertInventory
  658. );
  659. },
  660. //已售罄、警戒库存操作判断
  661. operation() {
  662. return (
  663. this.tableFrom.type == this.ProductTypeEnum.SoldOut ||
  664. this.tableFrom.type == this.ProductTypeEnum.AlertInventory
  665. );
  666. },
  667. //加入回收站 操作
  668. RecycleBin() {
  669. return (
  670. this.tableFrom.type == this.ProductTypeEnum.Audit ||
  671. this.tableFrom.type == this.ProductTypeEnum.ReviewFailed ||
  672. this.tableFrom.type === ProductTypeEnum.InTheWarehouse ||
  673. this.tableFrom.type === ProductTypeEnum.PendingReview
  674. );
  675. },
  676. ...mapGetters(['merPlatProductClassify', 'merProductClassify', 'productBrand', 'shippingTemplates']),
  677. },
  678. activated() {
  679. this.goodHeade();
  680. this.getList(1);
  681. },
  682. mounted() {
  683. if (checkPermi(['merchant:product:tabs:headers'])) this.goodHeade();
  684. if (checkPermi(['merchant:product:page:list'])) this.getList();
  685. if (!localStorage.getItem('shippingTemplates')) this.$store.dispatch('product/getShippingTemplates');
  686. this.checkedCities = this.$cache.local.has('goods_stroge')
  687. ? this.$cache.local.getJSON('goods_stroge')
  688. : this.checkedCities;
  689. //this.$store.dispatch('product/getAdminProductClassify');
  690. this.$store.dispatch('product/getAdminProductClassify');
  691. if (!localStorage.getItem('merProductClassify')) this.$store.dispatch('product/getMerProductClassify');
  692. this.$store.dispatch('product/getMerProductBrand');
  693. },
  694. methods: {
  695. checkPermi,
  696. //提交审核
  697. handlePendingReview(row) {
  698. if (!row && this.checkedIds.length === 0) return this.$message.warning('请至少选择一个商品');
  699. if (!row) {
  700. this.$modalSure(`确定要将此商品提交平台审核吗?`).then(() => {
  701. productBatchAuditApi({
  702. idList: this.checkedIds,
  703. }).then(() => {
  704. this.$message.success('批量提交审核成功');
  705. this.getList('');
  706. this.goodHeade();
  707. });
  708. });
  709. } else {
  710. this.$confirm('提审之后是否自动上架?', '提示', {
  711. confirmButtonText: '上架',
  712. cancelButtonText: '不用了',
  713. type: 'warning',
  714. distinguishCancelAndClose: true,
  715. closeOnClickModal: false,
  716. customClass: 'deleteConfirm',
  717. })
  718. .then(() => {
  719. this.productAudit({ id: row.id, isAutoUp: true });
  720. })
  721. .catch((action) => {
  722. if (action === 'cancel') {
  723. this.productAudit({ id: row.id, isAutoUp: false });
  724. // 调用取消按钮的方法
  725. } else if (action === 'close') {
  726. console.log('Closed');
  727. // 调用关闭按钮的方法
  728. }
  729. });
  730. }
  731. },
  732. //提审提交
  733. productAudit(data) {
  734. productAuditApi(data).then((res) => {
  735. this.goodHeade();
  736. this.getList();
  737. });
  738. },
  739. //批量加入回收站
  740. handleRecycleBin(type) {
  741. if (this.checkedIds.length === 0) return this.$message.warning('请至少选择一个商品');
  742. this.$modalSure(type == 5 ? `确定批量删除商品吗?` : `确定批量加入回收站吗?`).then(() => {
  743. if (type == 5) {
  744. this.onBatchDelete();
  745. } else {
  746. this.onBatchRecycle();
  747. }
  748. });
  749. },
  750. //批量删除
  751. onBatchDelete() {
  752. productBatchDeleteApi({
  753. idList: this.checkedIds,
  754. }).then(() => {
  755. this.$message.success('批量删除成功');
  756. this.tableFrom.page = this.tableFrom.page - 1;
  757. this.delSuccess();
  758. });
  759. },
  760. //批量加入回收站
  761. onBatchRecycle() {
  762. productBatchRecycleApi({
  763. idList: this.checkedIds,
  764. }).then(() => {
  765. this.$message.success('批量加入回收站成功');
  766. this.tableFrom.page = this.tableFrom.page - 1;
  767. this.delSuccess();
  768. });
  769. },
  770. // 删除成功
  771. delSuccess() {
  772. handleDeleteTable(this.tableData.data.length, this.tableFrom);
  773. this.getList();
  774. this.goodHeade();
  775. },
  776. //添加回馈券
  777. handleAddCoupon(row) {
  778. this.productInfo = row;
  779. if (!row && this.checkedIds.length === 0) return this.$message.warning('请至少选择一个商品');
  780. const _this = this;
  781. this.$modalCoupon(
  782. 'wu',
  783. (_this.keyNum += 1),
  784. [],
  785. function (row) {
  786. row.map((item) => {
  787. _this.couponIds.push(item.id);
  788. });
  789. _this.onSetCoupons(_this.couponIds);
  790. },
  791. '',
  792. );
  793. },
  794. //设置优惠券提交
  795. onSetCoupons(couponIds) {
  796. if (this.productInfo) {
  797. productAddCouponsApi({ id: this.productInfo.id, couponIds: couponIds }).then(() => {
  798. this.$message.success('添加回馈券成功');
  799. });
  800. } else {
  801. productBatchAddCouponsApi({ idList: this.checkedIds, couponIds: couponIds }).then(() => {
  802. this.$message.success('批量添加回馈券成功');
  803. });
  804. }
  805. },
  806. // 设置运费
  807. async handleSetFreight(row) {
  808. this.productInfo = row;
  809. if (!row && this.checkedIds.length === 0) return this.$message.warning('请至少选择一个商品');
  810. this.dialogVisible = true;
  811. if (row) this.formValidate.tempId = row.tempId;
  812. },
  813. //设置运费提交
  814. handleSubmit(name) {
  815. this.$refs[name].validate((valid) => {
  816. if (valid) {
  817. this.loadingBtn = true;
  818. if (this.productInfo) {
  819. productSetFreightApi({ id: this.productInfo.id, templateId: this.formValidate.tempId })
  820. .then(() => {
  821. this.loadingBtn = false;
  822. this.$message.success('设置运费模板成功');
  823. this.dialogVisible = false;
  824. })
  825. .catch(() => {
  826. this.loadingBtn = false;
  827. });
  828. } else {
  829. productBatchFreightApi({ idList: this.checkedIds, templateId: this.formValidate.tempId })
  830. .then(() => {
  831. this.loadingBtn = false;
  832. this.$message.success('批量设置运费模板成功');
  833. this.dialogVisible = false;
  834. })
  835. .catch(() => {
  836. this.loadingBtn = false;
  837. });
  838. }
  839. }
  840. });
  841. },
  842. //取消运费
  843. handleClose() {
  844. this.dialogVisible = false;
  845. this.formValidate.tempId = '';
  846. },
  847. //设置佣金
  848. handleSetCommission(row) {
  849. this.productInfo = row;
  850. if (!row && this.checkedIds.length === 0) return this.$message.warning('请至少选择一个商品');
  851. this.dialogCommision = true;
  852. },
  853. //设置佣金提交
  854. submitCommisionForm(name) {
  855. this.$refs[name].validate((valid) => {
  856. if (valid) {
  857. if (this.productInfo) {
  858. this.commisionForm.id = this.productInfo.id;
  859. productBrokerageApi(this.commisionForm).then(() => {
  860. this.$message.success('设置佣金成功');
  861. this.dialogCommision = false;
  862. });
  863. } else {
  864. this.commisionForm.idList = this.checkedIds;
  865. productBatchBrokerageApi(this.commisionForm).then(() => {
  866. this.$message.success('批量设置佣金成功');
  867. this.dialogCommision = false;
  868. });
  869. }
  870. } else {
  871. return;
  872. }
  873. });
  874. },
  875. //添加商品
  876. handleAdd(type) {
  877. this.addType = type;
  878. this.$refs.productTpye.proTypedialogVisible = true;
  879. },
  880. //批量下架
  881. batchDelisting(type) {
  882. if (this.checkedIds.length === 0) return this.$message.warning('请至少选择一个商品');
  883. if (type === 'down') {
  884. this.$modalSure('确定要将选中商品批量下架吗?').then(() => {
  885. productBatchDownApi({ idList: this.checkedIds }).then(() => {
  886. this.$message.success('批量下架成功');
  887. this.getList(1);
  888. this.goodHeade();
  889. });
  890. });
  891. } else {
  892. this.$modalSure('确定要将选中商品批量上架吗?').then(() => {
  893. productBatchUpApi({ idList: this.checkedIds }).then(() => {
  894. this.$message.success('批量上架成功');
  895. this.getList(1);
  896. this.goodHeade();
  897. });
  898. });
  899. }
  900. },
  901. // 设置选中的方法
  902. handleSelectionChange(val) {
  903. this.multipleSelectionAll = val;
  904. const data = [];
  905. this.multipleSelectionAll.map((item) => {
  906. data.push(item.id);
  907. });
  908. this.checkedIds = data;
  909. },
  910. selectAll(data) {
  911. let id = data.map((i, index) => {
  912. return i.id;
  913. });
  914. this.checkedIds = Array.from(new Set([...this.checkedIds, ...id]));
  915. },
  916. selectOne(data, row) {
  917. let id = data.map((i, index) => {
  918. return i.id;
  919. });
  920. let index = this.checkedIds.findIndex((e) => {
  921. return e == row.id;
  922. });
  923. this.checkedIds.splice(index, 1);
  924. this.checkedIds = Array.from(new Set([...this.checkedIds, ...id]));
  925. },
  926. //编辑商品
  927. onEdit(row) {
  928. //id:商品id,isDisabled:是否能编辑(1不能,2能),isCopy:是否是采集商品(1是,2不是)
  929. if (this.tableFrom.type === '1') {
  930. this.$modalSure('下架该商品吗?出售商品需下架之后可编辑。').then(() => {
  931. offShellApi(row.id).then(() => {
  932. this.$router.push({ path: `/product/list/creatProduct/${row.id}/2/2/${row.type}` });
  933. });
  934. });
  935. } else {
  936. this.$router.push({ path: `/product/list/creatProduct/${row.id}/2/2/${row.type}` });
  937. }
  938. },
  939. //编辑库存成功回调
  940. subSuccess() {
  941. this.drawer = false;
  942. this.handleSeachList();
  943. },
  944. handleEdit(row, stockEdit) {
  945. this.productId = row.id;
  946. this.productType = row.type;
  947. this.isSub = row.isSub;
  948. this.drawer = true;
  949. this.stockEdit = stockEdit;
  950. },
  951. handleCloseEdit() {
  952. this.drawer = false;
  953. },
  954. handleAudit(id) {
  955. // this.$modalSure('提审商品吗').then(() => {
  956. // productAuditApi(id).then((res) => {
  957. // this.goodHeade();
  958. // this.getList();
  959. // });
  960. // });
  961. this.$confirm('提审之后是否自动上架?', '提示', {
  962. confirmButtonText: '上架',
  963. cancelButtonText: '不用了',
  964. type: 'warning',
  965. showClose: false,
  966. closeOnClickModal: false,
  967. })
  968. .then(() => {
  969. this.productAudit({ id: id, isAutoUp: true });
  970. })
  971. .catch(() => {
  972. this.productAudit({ id: id, isAutoUp: false });
  973. });
  974. },
  975. //恢复商品
  976. handleRestore(row) {
  977. if (!row && this.checkedIds.length === 0) return this.$message.warning('请至少选择一个商品');
  978. this.$modalSure(!row ? '确定批量恢复商品吗?' : '确定恢复商品吗?').then(() => {
  979. if (row) {
  980. restoreApi(row.id).then((res) => {
  981. this.$message.success('恢复商品成功');
  982. this.goodHeade();
  983. this.getList(1);
  984. });
  985. } else {
  986. productBatchRestoreApi({ idList: this.checkedIds }).then((res) => {
  987. this.$message.success('批量恢复商品成功');
  988. this.goodHeade();
  989. this.getList(1);
  990. });
  991. }
  992. });
  993. },
  994. handleSeachList() {
  995. this.getList(1);
  996. this.goodHeade();
  997. },
  998. //重置
  999. handleReset() {
  1000. this.tableFrom.cateId = '';
  1001. this.tableFrom.keywords = '';
  1002. this.tableFrom.categoryId = '';
  1003. this.tableFrom.isPaidMember = null;
  1004. this.tableFrom.productType = null;
  1005. this.keywords = '';
  1006. this.handleSeachList();
  1007. },
  1008. // 导出
  1009. exports() {
  1010. productExcelApi({
  1011. cateId: this.tableFrom.cateId,
  1012. keywords: this.tableFrom.keywords,
  1013. type: this.tableFrom.type,
  1014. }).then((res) => {
  1015. window.location.href = res.fileName;
  1016. });
  1017. },
  1018. // 获取商品表单头数量
  1019. goodHeade() {
  1020. let data = Object.assign({}, this.tableFrom);
  1021. delete data.page;
  1022. delete data.limit;
  1023. delete data.type;
  1024. productHeadersApi(data)
  1025. .then((res) => {
  1026. res.map((item) => {
  1027. item.name = objTitle[Number(item.type) - 1];
  1028. });
  1029. this.headeNum = res;
  1030. })
  1031. .catch((res) => {
  1032. this.$message.error(res.message);
  1033. });
  1034. },
  1035. changeNodes(data) {
  1036. if (data.length > 0) {
  1037. for (var i = 0; i < data.length; i++) {
  1038. if (!data[i].childList || data[i].childList.length < 1) {
  1039. data[i].childList = undefined;
  1040. } else {
  1041. this.changeNodes(data[i].childList);
  1042. }
  1043. }
  1044. }
  1045. return data;
  1046. },
  1047. // 列表
  1048. getList(num) {
  1049. this.listLoading = true;
  1050. this.tableFrom.page = num ? num : this.tableFrom.page;
  1051. this.tableFrom.keywords = encodeURIComponent(this.keywords);
  1052. productLstApi(this.tableFrom)
  1053. .then((res) => {
  1054. this.tableData.data = res.list;
  1055. this.tableData.total = res.total;
  1056. this.listLoading = false;
  1057. })
  1058. .catch((res) => {
  1059. this.listLoading = false;
  1060. });
  1061. },
  1062. pageChange(page) {
  1063. this.tableFrom.page = page;
  1064. this.getList();
  1065. },
  1066. handleSizeChange(val) {
  1067. this.tableFrom.limit = val;
  1068. this.getList();
  1069. },
  1070. //详情
  1071. handleInfo(id, type) {
  1072. this.$router.push({ path: `/product/list/creatProduct/${id}/2/2/${type}` });
  1073. },
  1074. // 删除
  1075. handleDelete(id, type) {
  1076. this.$modalSure(type == 5 ? `删除 id 为 ${id} 的商品` : `id为${id}的商品加入回收站吗`).then(() => {
  1077. const deleteFlag = type == 5 ? 'delete' : 'recycle';
  1078. productDeleteApi({
  1079. id: id,
  1080. type: deleteFlag,
  1081. }).then(() => {
  1082. this.$message.success('删除成功');
  1083. this.delSuccess();
  1084. });
  1085. });
  1086. },
  1087. onchangeIsShow(row) {
  1088. row.isShow
  1089. ? putOnShellApi(row.id)
  1090. .then(() => {
  1091. this.$message.success('上架成功');
  1092. this.getList(1);
  1093. this.goodHeade();
  1094. })
  1095. .catch(() => {
  1096. row.isShow = !row.isShow;
  1097. })
  1098. : offShellApi(row.id)
  1099. .then(() => {
  1100. this.$message.success('下架成功');
  1101. this.getList(1);
  1102. this.goodHeade();
  1103. })
  1104. .catch(() => {
  1105. row.isShow = !row.isShow;
  1106. });
  1107. },
  1108. handleAddItem() {
  1109. if (this.card_select_show) {
  1110. this.$set(this, 'card_select_show', false);
  1111. } else if (!this.card_select_show) {
  1112. this.$set(this, 'card_select_show', true);
  1113. }
  1114. },
  1115. handleCheckAllChange(val) {
  1116. this.checkedCities = val ? this.columnData : [];
  1117. this.isIndeterminate = false;
  1118. },
  1119. handleCheckedCitiesChange(value) {
  1120. let checkedCount = value.length;
  1121. this.checkAll = checkedCount === this.columnData.length;
  1122. this.isIndeterminate = checkedCount > 0 && checkedCount < this.columnData.length;
  1123. },
  1124. checkSave() {
  1125. this.$set(this, 'card_select_show', false);
  1126. this.$modal.loading('正在保存到本地,请稍候...');
  1127. this.$cache.local.setJSON('goods_stroge', this.checkedCities);
  1128. setTimeout(this.$modal.closeLoading(), 1000);
  1129. },
  1130. },
  1131. };
  1132. </script>
  1133. <style scoped lang="scss">
  1134. .tags_name {
  1135. font-size: 12px;
  1136. height: 16px;
  1137. line-height: 16px;
  1138. padding: 0 2px;
  1139. margin-right: 2px;
  1140. &.namefalse {
  1141. color: var(--prev-color-primary);
  1142. }
  1143. &.nametrue {
  1144. color: #ff8a4d;
  1145. }
  1146. }
  1147. ::v-deep .el-table__cell:nth-child(2) .cell {
  1148. padding-left: 14px;
  1149. padding-right: 14px;
  1150. }
  1151. .infoItem {
  1152. ::v-deep a {
  1153. color: #606266 !important;
  1154. }
  1155. }
  1156. .el-table__body {
  1157. width: 100%;
  1158. table-layout: fixed !important;
  1159. }
  1160. .taoBaoModal {
  1161. // z-index: 3333 !important;
  1162. }
  1163. .demo-table-expand {
  1164. ::v-deep label {
  1165. width: 82px;
  1166. }
  1167. }
  1168. .demo-table-expand {
  1169. ::v-deep .el-form-item__content {
  1170. width: 77%;
  1171. }
  1172. }
  1173. .seachTiele {
  1174. line-height: 30px;
  1175. }
  1176. .relative {
  1177. position: relative;
  1178. }
  1179. .card_abs {
  1180. position: absolute;
  1181. padding-bottom: 15px;
  1182. top: 260px;
  1183. right: 40px;
  1184. width: 200px;
  1185. background: #fff;
  1186. z-index: 99999;
  1187. box-shadow: 0px 0px 14px 0px rgba(0, 0, 0, 0.1);
  1188. }
  1189. .cell_ht {
  1190. height: 50px;
  1191. padding: 15px 20px;
  1192. box-sizing: border-box;
  1193. border-bottom: 1px solid #eeeeee;
  1194. display: flex;
  1195. justify-content: space-between;
  1196. align-items: center;
  1197. }
  1198. .check_cell {
  1199. width: 100%;
  1200. padding: 15px 20px 0;
  1201. }
  1202. .mt-1 {
  1203. margin-top: 6px;
  1204. }
  1205. ::v-deep .el-checkbox__input.is-checked + .el-checkbox__label {
  1206. color: #606266;
  1207. }
  1208. ::v-deep .el-drawer__header {
  1209. font-size: 20px;
  1210. }
  1211. ::v-deep .el-drawer__close-btn {
  1212. font-size: 20px;
  1213. }
  1214. ::v-deep .el-dialog__footer {
  1215. padding: 0 24px 20px !important;
  1216. }
  1217. </style>