list.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. <template>
  2. <div class="app-container">
  3. <el-tabs v-model="activeName" type="border-card" @tab-click="handleClick">
  4. <el-tab-pane label="商品列表" name="first" />
  5. <el-tab-pane label="宣传图" name="second" />
  6. <template v-if="activeName === 'first'">
  7. <div class="filter-container">
  8. <div class="filter-control">
  9. <span>商品ID:</span>
  10. <el-input
  11. v-model="listQuery.productId"
  12. placeholder="商品ID"
  13. clearable
  14. @input="e => (listQuery.productId= checkedInput(e,1))"
  15. @keyup.enter.native="getList"
  16. @clear="getList"
  17. />
  18. </div>
  19. <div class="filter-control">
  20. <span>商品名称:</span>
  21. <el-input
  22. v-model="listQuery.productName"
  23. placeholder="商品名称"
  24. clearable
  25. @input="e => (listQuery.productName= checkedInput(e,2))"
  26. @keyup.enter.native="getList"
  27. @clear="getList"
  28. />
  29. </div>
  30. <div class="filter-control">
  31. <span>供应商:</span>
  32. <el-input
  33. v-model="listQuery.shopName"
  34. placeholder="供应商"
  35. clearable
  36. @keyup.enter.native="getList"
  37. @clear="getList"
  38. />
  39. </div>
  40. <div class="filter-control">
  41. <span>优惠状态:</span>
  42. <el-select v-model="listQuery.status" style="width:120px;" clearable @change="getList">
  43. <el-option value="" label="请选择" />
  44. <el-option :value="0" label="已上架" />
  45. <el-option :value="1" label="已下架" />
  46. </el-select>
  47. </div>
  48. <div class="filter-control">
  49. <el-button type="primary" @click="getList">查询</el-button>
  50. <el-button type="primary" @click="proDialogVisible =true">添加</el-button>
  51. </div>
  52. </div>
  53. <el-table v-loading="isLoading" :data="tableData" border style="width: 100%">
  54. <el-table-column prop="productId" label="商品ID" align="center" />
  55. <el-table-column prop="coupon" label="商品图片" align="center">
  56. <template v-if="row.productId" slot-scope="{ row }">
  57. <el-popover
  58. placement="top-start"
  59. title=""
  60. width="180"
  61. trigger="hover"
  62. >
  63. <img :src="row.productImage" alt="" style="width:100px;height:100px;">
  64. <img slot="reference" :src="row.productImage" alt="" style="width:50px;height:50px;">
  65. </el-popover>
  66. </template>
  67. </el-table-column>
  68. <el-table-column prop="productName" label="商品名称" align="center" />
  69. <el-table-column prop="shopName" label="供应商" align="center" width="250" />
  70. <el-table-column prop="price" label="机构价" align="center" />
  71. <el-table-column prop="discount" label="会员折扣" align="center">
  72. <template slot-scope="{ row }">
  73. {{ row.priceType === 1 ? row.discount+'%' : '---' }}
  74. </template>
  75. </el-table-column>
  76. <el-table-column prop="discountPrice" label="会员价" align="center">
  77. <template slot-scope="{ row }">
  78. ¥{{ row.priceType === 2 ? row.discountPrice : row.price * row.discount * 0.01 }}
  79. </template>
  80. </el-table-column>
  81. <el-table-column label="排序" width="80" align="center">
  82. <template slot-scope="{row}">
  83. <el-input v-model="row.sort" maxlength="4" minlength="1" @blur="handleOnInputBlur(row)" />
  84. </template>
  85. </el-table-column>
  86. <el-table-column prop="status" label="优惠状态" align="center" width="100">
  87. <template slot-scope="{ row }">
  88. <span v-if="row.status === 0" class="el-span-zero">
  89. 已上架
  90. </span>
  91. <span v-else class="el-span-one">
  92. 已下架
  93. </span>
  94. </template>
  95. </el-table-column>
  96. <el-table-column prop="addTime" label="添加时间" align="center" width="100" />
  97. <el-table-column label="操作" align="center" width="180">
  98. <template slot-scope="{ row }">
  99. <el-button type="primary" size="mini" @click="handleEdit(row.id)">编辑</el-button>
  100. <el-button type="danger" size="mini" @click="handeleDelPro(row.id)">删除</el-button>
  101. </template>
  102. </el-table-column>
  103. </el-table>
  104. <!-- 页码 -->
  105. <pagination
  106. :total="total"
  107. :page-sizes="[20]"
  108. :page-size="20"
  109. :page.sync="listQuery.pageNum"
  110. :limit.sync="listQuery.pageSize"
  111. />
  112. <!-- 选择商品弹窗 -->
  113. <pro-dialog v-if="proDialogVisible" ref="proDialog" @confirm="handleAddProductConfirm" @cancel="handleCancel" />
  114. <!-- 商品编辑弹窗 -->
  115. <pro-edit v-if="proEditVisible" ref="proEdit" :pro-id="handleProId" @confirm="handleEditConfirm" @cancel="handleEditCancel" />
  116. </template>
  117. <template v-else>
  118. <div class="club-container" style="width: 100%;height: 650px;padding-top: 40px;">
  119. <el-form ref="submitForm" class="doctor-edit-form" label-width="140px" :model="formData" :rules="rules">
  120. <el-form-item label="PC端:" prop="doctorImage">
  121. <div class="form-label-tip">宣传图</div>
  122. <el-input v-show="false" v-model="formData.pcImage" />
  123. <upload-image
  124. tip="提示:建议图片分辨率1920px*510px"
  125. :image-list="pcImageList"
  126. :before-upload="beforeDoctorImageUpload"
  127. @success="uploadDoctorImageSuccess"
  128. @remove="handleDoctorImageRemove"
  129. />
  130. </el-form-item>
  131. <el-form-item label="小程序端:" prop="banner">
  132. <div class="form-label-tip">宣传图</div>
  133. <el-input v-show="false" v-model="formData.appletsImage" />
  134. <upload-image
  135. tip="提示:建议图片分辨率351px*170px"
  136. :image-list="appletsImageList"
  137. :before-upload="beforeBannerUpload"
  138. @success="uploadBannerSuccess"
  139. @remove="handleBannerRemove"
  140. />
  141. </el-form-item>
  142. </el-form>
  143. <div class="submit-btn" style="padding-left: 137px;">
  144. <el-button type="primary" :disabled="disabled" @click="submitSave">保存</el-button>
  145. </div>
  146. </div>
  147. </template>
  148. </el-tabs>
  149. </div>
  150. </template>
  151. <script>
  152. import { fetchFindProductList, updateSort, saveAdsImage, getAdsImage } from '@/api/member/member'
  153. import { delSvipProduct, saveSvipProduct } from '@/api/member/member'
  154. import UploadImage from '@/components/UploadImage'
  155. import ProDialog from './components/pro-dialog'
  156. import ProEdit from './components/pro-edit'
  157. export default {
  158. name: 'MemberProduct',
  159. components: { UploadImage, ProDialog, ProEdit },
  160. data() {
  161. return {
  162. activeName: 'first',
  163. listQuery: {
  164. productId: null,
  165. productName: '',
  166. shopName: '',
  167. status: '',
  168. pageNum: 0,
  169. pageSize: 20
  170. },
  171. formData: {
  172. pcImage: '',
  173. appletsImage: ''
  174. },
  175. // PC端宣传图
  176. pcImageList: [],
  177. // 小程序端宣传图
  178. appletsImageList: [],
  179. rules: {
  180. pcImage: [{ required: true, message: '请上传PC端宣传图', trigger: 'change' }],
  181. appletsImage: [{ required: true, message: '请上传小程序端宣传图', trigger: 'change' }]
  182. },
  183. // 超级会员商品列表
  184. total: 0,
  185. isLoading: true,
  186. tableData: [],
  187. proDialogVisible: false,
  188. proEditVisible: false,
  189. handleProId: null
  190. }
  191. },
  192. computed: {
  193. disabled() {
  194. return !(this.formData.pcImage !== '' > 0 && this.formData.appletsImage !== '')
  195. }
  196. },
  197. created() {
  198. this.getList()
  199. },
  200. methods: {
  201. async getList() {
  202. this.isLoading = true
  203. const res = await fetchFindProductList(this.listQuery)
  204. this.tableData = res.data.results
  205. this.total = res.data.totalRecord
  206. this.isLoading = false
  207. },
  208. handleOnInputBlur(row) {
  209. // 更新排序
  210. updateSort({ id: row.id, sort: row.sort }).then(response => {
  211. this.$message({
  212. message: '操作成功',
  213. type: 'success',
  214. duration: 1000
  215. })
  216. this.getList()
  217. })
  218. },
  219. // tab切换
  220. handleClick(tab, event) {
  221. if (tab.name === 'second') {
  222. this.getAdsImageData()
  223. }
  224. },
  225. async getAdsImageData() {
  226. try {
  227. this.pcImageList = []
  228. this.appletsImageList = []
  229. const res = await getAdsImage(this.formData)
  230. console.log('res', res.data)
  231. this.formData.pcImage = res.data.pcImage
  232. this.formData.appletsImage = res.data.appletsImage
  233. this.pcImageList.push({ url: res.data.pcImage, name: 'doctor' })
  234. this.appletsImageList.push({ url: res.data.appletsImage, name: 'doctor' })
  235. console.log('pcImageList', this.pcImageList)
  236. console.log('appletsImageList', this.appletsImageList)
  237. } catch (error) {
  238. console.log(error)
  239. }
  240. },
  241. async submitSave() {
  242. // 保存
  243. try {
  244. console.log('formData', this.formData)
  245. await saveAdsImage(this.formData)
  246. this.$message.success('保存成功')
  247. setTimeout(() => {
  248. this.getAdsImageData()
  249. }, 2000)
  250. } catch (error) {
  251. console.log(error)
  252. }
  253. },
  254. // PC端宣传图上传
  255. uploadDoctorImageSuccess({ response, file, fileList }) {
  256. this.pcImageList = fileList
  257. this.formData.pcImage = response.data
  258. },
  259. handleDoctorImageRemove({ file, fileList }) {
  260. this.pcImageList = fileList
  261. this.formData.pcImage = ''
  262. },
  263. beforeDoctorImageUpload(file) {
  264. const flag = file.size / 1024 / 1024 < 2
  265. if (!flag) {
  266. this.$message.error('上传图片大小不能超过 2MB!')
  267. }
  268. return flag
  269. },
  270. // 小程序端宣传图上传
  271. uploadBannerSuccess({ response, file, fileList }) {
  272. this.appletsImageList = fileList
  273. this.formData.appletsImage = fileList.length || ''
  274. },
  275. handleBannerRemove({ file, fileList }) {
  276. this.appletsImageList = fileList
  277. this.formData.appletsImage = fileList.length || ''
  278. },
  279. beforeBannerUpload(file) {
  280. const flag = file.size / 1024 / 1024 < 2
  281. if (!flag) {
  282. this.$message.error('上传图片大小不能超过 2MB!')
  283. }
  284. return flag
  285. },
  286. async handeleDelPro(id) {
  287. await this.$confirm('确认要删除该商品吗?', {
  288. confirmButtonText: '确定',
  289. cancelButtonText: '取消',
  290. type: 'warning'
  291. })
  292. this.delSvipProductSubmit(id)
  293. },
  294. async delSvipProductSubmit(id) {
  295. try {
  296. await delSvipProduct(id)
  297. this.$message.success('操作成功')
  298. this.getList()
  299. } catch (error) {
  300. console.log(error)
  301. }
  302. },
  303. async handleAddProductConfirm(productId) {
  304. // 确认添加商品
  305. try {
  306. await saveSvipProduct({ productId: productId })
  307. this.$message.success('添加成功')
  308. this.handleCancel()
  309. this.getList()
  310. } catch (error) {
  311. console.log(error)
  312. }
  313. },
  314. handleCancel() {
  315. // 取消选择添加商品
  316. this.proDialogVisible = false
  317. this.$refs.proDialog.visible = false
  318. },
  319. handleEdit(id) {
  320. // 编辑商品
  321. this.handleProId = id
  322. this.proEditVisible = true
  323. },
  324. handleEditCancel() {
  325. // 取消编辑商品
  326. this.proEditVisible = false
  327. this.$refs.proEdit.visible = false
  328. },
  329. async handleEditConfirm(data) {
  330. // 保存编辑商品
  331. console.log('data', data)
  332. try {
  333. await saveSvipProduct(data)
  334. this.$message.success('操作成功')
  335. this.handleEditCancel()
  336. this.getList()
  337. } catch (error) {
  338. console.log(error)
  339. }
  340. },
  341. checkedInput(event, type) {
  342. let pattern = ''
  343. switch (type) {
  344. case 1:
  345. pattern = /[^\d]/g
  346. break
  347. case 2:
  348. pattern = /[^u4E00-u9FA5|d|a-zA-Z|rns,.?!,。?!…—&$=()-+/*{}[]]|s/g
  349. break
  350. }
  351. return event.replace(pattern, '')
  352. }
  353. }
  354. }
  355. </script>
  356. <style>
  357. .el-span-zero {
  358. color: #0bd81c;
  359. }
  360. .el-span-one {
  361. color: #ff353f;
  362. }
  363. </style>