DishManagement.vue 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. <template>
  2. <div class="page">
  3. <el-form :inline="true" v-if="searchVisible" class="query-form m-b-10" ref="searchForm" :model="searchForm"
  4. @keyup.enter.native="refreshList()" @submit.native.prevent>
  5. <el-form-item label="菜品名称" prop="name">
  6. <el-input v-model="searchForm.name" placeholder="请输入菜品名称" clearable></el-input>
  7. </el-form-item>
  8. <el-form-item label="分类" prop="categoryId">
  9. <el-select v-model="searchForm.categoryId" placeholder="请选择分类" clearable style="width: 140px">
  10. <el-option v-for="item in categoryList" :key="item.id" :label="item.name" :value="item.id"></el-option>
  11. </el-select>
  12. </el-form-item>
  13. <el-form-item label="状态" prop="status">
  14. <el-select v-model="searchForm.status" placeholder="请选择状态" clearable style="width: 120px">
  15. <el-option label="在售" value="ON_SALE"></el-option>
  16. <el-option label="下架" value="OFF_SHELF"></el-option>
  17. </el-select>
  18. </el-form-item>
  19. <el-form-item>
  20. <el-button type="primary" @click="refreshList()" icon="el-icon-search">查询</el-button>
  21. <el-button @click="resetSearch()" icon="el-icon-refresh-right">重置</el-button>
  22. </el-form-item>
  23. </el-form>
  24. <div class="jp-table top">
  25. <vxe-toolbar :refresh="{ query: refreshList }" custom>
  26. <template #buttons>
  27. <el-button v-if="hasPermission('hotel:admin:dish:add')" type="primary" icon="el-icon-plus"
  28. @click="add()">新建</el-button>
  29. <el-button v-if="hasPermission('hotel:admin:dish:delete')" type="danger" icon="el-icon-delete"
  30. @click="batchDelete()"
  31. :disabled="$refs.dataTable && $refs.dataTable.getCheckboxRecords().length === 0"
  32. plain>删除</el-button>
  33. </template>
  34. <template #tools>
  35. <vxe-button text type="primary" :title="searchVisible ? '收起检索' : '展开检索'" icon="vxe-icon-search"
  36. class="tool-btn" @click="searchVisible = !searchVisible"></vxe-button>
  37. </template>
  38. </vxe-toolbar>
  39. <div style="height: calc(100% - 90px)">
  40. <vxe-table border="inner" auto-resize resizable height="auto" :loading="loading" ref="dataTable"
  41. show-header-overflow show-overflow highlight-hover-row :menu-config="{}" :data="dataList"
  42. :checkbox-config="{}">
  43. <vxe-column type="seq" width="60" title="序号"></vxe-column>
  44. <vxe-column type="checkbox" width="60"></vxe-column>
  45. <vxe-column width="80" align="center" title="菜品图片" field="image">
  46. <template #default="scope">
  47. <el-image v-if="scope.row.previewImageUrl" :src="scope.row.previewImageUrl"
  48. :preview-src-list="scope.row.previewImageList" fit="cover"
  49. style="width: 44px; height: 44px; border-radius: 4px;" hide-on-click-modal
  50. append-to-body :z-index="9999"></el-image>
  51. <span v-else>暂无图片</span>
  52. </template>
  53. </vxe-column>
  54. <vxe-column min-width="150" align="left" title="菜品名称" field="name"></vxe-column>
  55. <vxe-column width="100" align="center" title="分类" field="categoryName"></vxe-column>
  56. <vxe-column width="90" align="right" title="价格" field="price">
  57. <template #default="scope">¥{{ scope.row.price }}</template>
  58. </vxe-column>
  59. <vxe-column width="100" align="center" title="制作时长" field="prepTime">
  60. <template #default="scope">{{ scope.row.prepTime ? scope.row.prepTime + '分钟' : '-' }}</template>
  61. </vxe-column>
  62. <vxe-column width="80" align="center" title="月销" field="sales"></vxe-column>
  63. <vxe-column width="100" align="center" title="状态" field="status">
  64. <template #default="scope">
  65. <el-tag :type="scope.row.status === 'ON_SALE' ? 'success' : 'info'">
  66. {{ scope.row.status === 'ON_SALE' ? '在售' : '下架' }}
  67. </el-tag>
  68. </template>
  69. </vxe-column>
  70. <vxe-column width="80" align="center" title="售罄" field="soldOut">
  71. <template #default="scope">
  72. <el-tag v-if="scope.row.soldOut === 1" type="danger">售罄</el-tag>
  73. <span v-else>-</span>
  74. </template>
  75. </vxe-column>
  76. <vxe-column width="80" align="center" title="推荐" field="isRecommended">
  77. <template #default="scope">
  78. <el-tag v-if="scope.row.isRecommended === 1" type="warning">推荐</el-tag>
  79. <span v-else>-</span>
  80. </template>
  81. </vxe-column>
  82. <vxe-column width="70" align="center" title="排序" field="sortOrder"></vxe-column>
  83. <vxe-column title="操作" width="220px" fixed="right" align="center">
  84. <template #default="scope">
  85. <el-button v-if="hasPermission('hotel:admin:dish:edit')" text type="primary" size="small"
  86. @click="edit(scope.row.id)">修改</el-button>
  87. <el-button v-if="hasPermission('hotel:admin:dish:edit')" text type="primary" size="small"
  88. @click="changeStatus(scope.row)">{{ scope.row.status === 'ON_SALE' ? '下架' : '上架' }}</el-button>
  89. <el-button v-if="hasPermission('hotel:admin:dish:delete')" text type="primary" size="small"
  90. @click="doDelete(scope.row.id)">删除</el-button>
  91. </template>
  92. </vxe-column>
  93. </vxe-table>
  94. <vxe-pager background :current-page="tablePage.currentPage" :page-size="tablePage.pageSize"
  95. :total="tablePage.total" :page-sizes="[10, 20, 100, 1000, { label: '全量数据', value: 1000000 }]"
  96. :layouts="['PrevPage', 'JumpNumber', 'NextPage', 'FullJump', 'Sizes', 'Total']"
  97. @page-change="currentChangeHandle">
  98. </vxe-pager>
  99. </div>
  100. </div>
  101. <DishForm ref="dishForm" @refreshList="refreshList"></DishForm>
  102. </div>
  103. </template>
  104. <script>
  105. import HotelDishService from '@/api/hotel/HotelDishService'
  106. import DishForm from './DishForm'
  107. import OSSSerivce from '@/api/sys/OSSService'
  108. export default {
  109. data() {
  110. return {
  111. searchVisible: true,
  112. searchForm: {
  113. name: '',
  114. categoryId: '',
  115. status: ''
  116. },
  117. categoryList: [],
  118. dataList: [],
  119. tablePage: {
  120. total: 0,
  121. currentPage: 1,
  122. pageSize: 10,
  123. orders: []
  124. },
  125. loading: false
  126. }
  127. },
  128. hotelDishService: null,
  129. ossService: null,
  130. created() {
  131. this.hotelDishService = new HotelDishService()
  132. this.ossService = new OSSSerivce()
  133. },
  134. components: {
  135. DishForm
  136. },
  137. mounted() {
  138. this.refreshList()
  139. this.loadCategories()
  140. },
  141. activated() {
  142. this.refreshList()
  143. },
  144. methods: {
  145. add() {
  146. this.$refs.dishForm.init('add', '')
  147. },
  148. edit(id) {
  149. this.$refs.dishForm.init('edit', id)
  150. },
  151. loadCategories() {
  152. this.hotelDishService.categoryAll().then((data) => {
  153. this.categoryList = Array.isArray(data) ? data : (data.list || [])
  154. })
  155. },
  156. refreshList() {
  157. this.loading = true
  158. this.hotelDishService.page({
  159. 'current': this.tablePage.currentPage,
  160. 'size': this.tablePage.pageSize,
  161. 'orders': this.tablePage.orders,
  162. ...this.searchForm
  163. }).then((data) => {
  164. this.dataList = data.records || []
  165. this.tablePage.total = data.total || 0
  166. this.loading = false
  167. this.loadImagePreview()
  168. }).catch(() => {
  169. this.loading = false
  170. })
  171. },
  172. loadImagePreview() {
  173. this.dataList.forEach((row) => {
  174. const urls = this.getImageUrls(row.image)
  175. if (urls.length === 0) {
  176. row.previewImageUrl = ''
  177. row.previewImageList = []
  178. return
  179. }
  180. row.previewImageList = urls
  181. row.previewImageUrl = urls[0]
  182. Promise.all(urls.map(url => this.getPreviewUrl(url))).then((list) => {
  183. row.previewImageList = list
  184. row.previewImageUrl = list[0]
  185. })
  186. })
  187. },
  188. getImageUrls(value) {
  189. if (!value) {
  190. return []
  191. }
  192. return value.split(',').map(item => item.trim()).filter(item => item)
  193. },
  194. getPreviewUrl(url) {
  195. if (url.indexOf('http') === 0) {
  196. return Promise.resolve(url)
  197. }
  198. return this.ossService.getTemporaryUrl(url).catch(() => url)
  199. },
  200. currentChangeHandle({ currentPage, pageSize }) {
  201. this.tablePage.currentPage = currentPage
  202. this.tablePage.pageSize = pageSize
  203. this.refreshList()
  204. },
  205. changeStatus(row) {
  206. const status = row.status === 'ON_SALE' ? 'OFF_SHELF' : 'ON_SALE'
  207. const message = status === 'ON_SALE' ? '确定上架该菜品吗?' : '确定下架该菜品吗?'
  208. this.$confirm(message, '提示', {
  209. confirmButtonText: '确定',
  210. cancelButtonText: '取消',
  211. type: 'warning'
  212. }).then(() => {
  213. this.hotelDishService.updateStatus(row.id, status).then((data) => {
  214. this.$message.success(data)
  215. this.refreshList()
  216. })
  217. })
  218. },
  219. doDelete(id) {
  220. this.$confirm('确定删除该菜品吗?删除后不可恢复!', '提示', {
  221. confirmButtonText: '确定',
  222. cancelButtonText: '取消',
  223. type: 'warning'
  224. }).then(() => {
  225. this.loading = true
  226. this.hotelDishService.delete(id).then((data) => {
  227. this.$message.success(data)
  228. this.refreshList()
  229. this.loading = false
  230. }).catch(() => {
  231. this.loading = false
  232. })
  233. })
  234. },
  235. batchDelete() {
  236. const ids = this.$refs.dataTable.getCheckboxRecords().map(item => item.id).join(',')
  237. this.$confirm(`确定删除所选的 ${ids.split(',').length} 个菜品吗?`, '提示', {
  238. confirmButtonText: '确定',
  239. cancelButtonText: '取消',
  240. type: 'warning'
  241. }).then(() => {
  242. this.loading = true
  243. this.hotelDishService.batch({ ids: ids.split(','), operation: 'DELETE' }).then((data) => {
  244. this.$message.success(data)
  245. this.refreshList()
  246. this.loading = false
  247. }).catch(() => {
  248. this.loading = false
  249. })
  250. })
  251. },
  252. resetSearch() {
  253. this.$refs.searchForm.resetFields()
  254. this.searchForm.categoryId = ''
  255. this.tablePage.currentPage = 1
  256. this.refreshList()
  257. }
  258. }
  259. }
  260. </script>