Commit 7f2cddcbb7c26f652d4c8c7b2cbbe684d38ee789

Authored by wuxw
1 parent 5c5dc3cd

开发完成营销功能

src/api/mall/convenienceMenusManageApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 获取便民服务菜单列表
  4 +export function getConvenienceMenusList(params) {
  5 + return new Promise((resolve, reject) => {
  6 + request({
  7 + url: '/convenienceMenus/queryConvenienceMenus',
  8 + method: 'get',
  9 + params
  10 + }).then(response => {
  11 + const res = response.data
  12 + if (res.code == 0) {
  13 + resolve({
  14 + data: res.data,
  15 + total: res.total
  16 + })
  17 + } else {
  18 + reject(new Error(res.msg || '获取便民服务菜单列表失败'))
  19 + }
  20 + }).catch(error => {
  21 + reject(error)
  22 + })
  23 + })
  24 +}
  25 +
  26 +// 添加便民服务菜单
  27 +export function addConvenienceMenus(data) {
  28 + return new Promise((resolve, reject) => {
  29 + request({
  30 + url: '/convenienceMenus/saveConvenienceMenus',
  31 + method: 'post',
  32 + data
  33 + }).then(response => {
  34 + const res = response.data
  35 + if (res.code == 0) {
  36 + resolve(res)
  37 + } else {
  38 + reject(new Error(res.msg || '添加便民服务菜单失败'))
  39 + }
  40 + }).catch(error => {
  41 + reject(error)
  42 + })
  43 + })
  44 +}
  45 +
  46 +// 删除便民服务菜单
  47 +export function deleteConvenienceMenus(data) {
  48 + return new Promise((resolve, reject) => {
  49 + request({
  50 + url: '/convenienceMenus/deleteConvenienceMenus',
  51 + method: 'post',
  52 + data
  53 + }).then(response => {
  54 + const res = response.data
  55 + if (res.code == 0) {
  56 + resolve(res)
  57 + } else {
  58 + reject(new Error(res.msg || '删除便民服务菜单失败'))
  59 + }
  60 + }).catch(error => {
  61 + reject(error)
  62 + })
  63 + })
  64 +}
  65 +
  66 +// 上传文件
  67 +export function uploadFile(data) {
  68 + return new Promise((resolve, reject) => {
  69 + request({
  70 + url: '/uploadFile',
  71 + method: 'post',
  72 + data,
  73 + headers: {
  74 + 'Content-Type': 'multipart/form-data'
  75 + }
  76 + }).then(response => {
  77 + const res = response.data
  78 + if (res.code == 0) {
  79 + resolve(res)
  80 + } else {
  81 + reject(new Error(res.msg || '上传文件失败'))
  82 + }
  83 + }).catch(error => {
  84 + reject(error)
  85 + })
  86 + })
  87 +}
0 88 \ No newline at end of file
... ...
src/api/mall/storeInfoManageApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 查询商户信息列表
  4 +export function queryStoreInfo(params) {
  5 + return new Promise((resolve, reject) => {
  6 + request({
  7 + url: '/storeInfo/queryStoreInfo',
  8 + method: 'get',
  9 + params
  10 + }).then(response => {
  11 + const res = response.data
  12 + if (res.code === 0) {
  13 + resolve({
  14 + data: res.data,
  15 + total: res.total
  16 + })
  17 + } else {
  18 + reject(new Error(res.msg || 'Failed to query store info'))
  19 + }
  20 + }).catch(error => {
  21 + reject(error)
  22 + })
  23 + })
  24 +}
  25 +
  26 +// 查询便民菜单列表
  27 +export function queryConvenienceMenus(params) {
  28 + return new Promise((resolve, reject) => {
  29 + request({
  30 + url: '/convenienceMenus/queryConvenienceMenus',
  31 + method: 'get',
  32 + params
  33 + }).then(response => {
  34 + const res = response.data
  35 + if (res.code === 0) {
  36 + resolve({
  37 + data: res.data,
  38 + total: res.total
  39 + })
  40 + } else {
  41 + reject(new Error(res.msg || 'Failed to query convenience menus'))
  42 + }
  43 + }).catch(error => {
  44 + reject(error)
  45 + })
  46 + })
  47 +}
  48 +
  49 +// 保存商户信息
  50 +export function saveStoreInfo(data) {
  51 + return new Promise((resolve, reject) => {
  52 + request({
  53 + url: '/storeInfo/saveStoreInfo',
  54 + method: 'post',
  55 + data
  56 + }).then(response => {
  57 + const res = response.data
  58 + if (res.code === 0) {
  59 + resolve(res)
  60 + } else {
  61 + reject(new Error(res.msg || 'Failed to save store info'))
  62 + }
  63 + }).catch(error => {
  64 + reject(error)
  65 + })
  66 + })
  67 +}
  68 +
  69 +// 更新商户信息
  70 +export function updateStoreInfo(data) {
  71 + return new Promise((resolve, reject) => {
  72 + request({
  73 + url: '/storeInfo/updateStoreInfo',
  74 + method: 'post',
  75 + data
  76 + }).then(response => {
  77 + const res = response.data
  78 + if (res.code === 0) {
  79 + resolve(res)
  80 + } else {
  81 + reject(new Error(res.msg || 'Failed to update store info'))
  82 + }
  83 + }).catch(error => {
  84 + reject(error)
  85 + })
  86 + })
  87 +}
  88 +
  89 +// 删除商户信息
  90 +export function deleteStoreInfo(data) {
  91 + return new Promise((resolve, reject) => {
  92 + request({
  93 + url: '/storeInfo/deleteStoreInfo',
  94 + method: 'post',
  95 + data
  96 + }).then(response => {
  97 + const res = response.data
  98 + if (res.code === 0) {
  99 + resolve(res)
  100 + } else {
  101 + reject(new Error(res.msg || 'Failed to delete store info'))
  102 + }
  103 + }).catch(error => {
  104 + reject(error)
  105 + })
  106 + })
  107 +}
  108 +
  109 +// 上传文件
  110 +export function uploadFile(data) {
  111 + return new Promise((resolve, reject) => {
  112 + request({
  113 + url: '/uploadFile',
  114 + method: 'post',
  115 + data,
  116 + headers: {
  117 + 'Content-Type': 'multipart/form-data'
  118 + }
  119 + }).then(response => {
  120 + const res = response.data
  121 + if (res.code === 0) {
  122 + resolve(res)
  123 + } else {
  124 + reject(new Error(res.msg || 'Failed to upload file'))
  125 + }
  126 + }).catch(error => {
  127 + reject(error)
  128 + })
  129 + })
  130 +}
0 131 \ No newline at end of file
... ...
src/components/mall/AddConvenienceMenus.vue 0 → 100644
  1 +<template>
  2 + <el-dialog :title="$t('convenienceMenus.addTitle')" :visible.sync="visible" width="50%" @close="handleClose">
  3 + <el-form ref="form" :model="form" :rules="rules" label-width="120px">
  4 + <el-form-item :label="$t('convenienceMenus.menuName')" prop="name">
  5 + <el-input v-model="form.name" :placeholder="$t('convenienceMenus.menuNamePlaceholder')" />
  6 + </el-form-item>
  7 + <el-form-item :label="$t('convenienceMenus.imageUrl')" prop="icon">
  8 + <upload-image-url ref="uploadImage" @uploadCoverImage="handleImageChange" />
  9 + </el-form-item>
  10 + <el-form-item :label="$t('convenienceMenus.pagePath')" prop="url">
  11 + <el-input v-model="form.url" :placeholder="$t('convenienceMenus.pagePathPlaceholder')" />
  12 + </el-form-item>
  13 + <el-form-item :label="$t('convenienceMenus.displayOrder')" prop="seq">
  14 + <el-input-number v-model="form.seq" :min="1" />
  15 + </el-form-item>
  16 + <el-form-item :label="$t('convenienceMenus.remark')" prop="remark">
  17 + <el-input v-model="form.remark" type="textarea" :rows="3" />
  18 + </el-form-item>
  19 + </el-form>
  20 +
  21 + <span slot="footer" class="dialog-footer">
  22 + <el-button @click="visible = false">{{ $t('common.cancel') }}</el-button>
  23 + <el-button type="primary" @click="handleSubmit">{{ $t('common.confirm') }}</el-button>
  24 + </span>
  25 + </el-dialog>
  26 +</template>
  27 +
  28 +<script>
  29 +import { addConvenienceMenus } from '@/api/mall/convenienceMenusManageApi'
  30 +import UploadImageUrl from '@/components/upload/UploadImageUrl'
  31 +
  32 +export default {
  33 + name: 'AddConvenienceMenus',
  34 + components: {
  35 + UploadImageUrl
  36 + },
  37 + data() {
  38 + return {
  39 + visible: false,
  40 + form: {
  41 + name: '',
  42 + icon: '',
  43 + url: '',
  44 + seq: 1,
  45 + remark: ''
  46 + },
  47 + rules: {
  48 + name: [
  49 + { required: true, message: this.$t('convenienceMenus.menuNameRequired'), trigger: 'blur' },
  50 + { max: 50, message: this.$t('convenienceMenus.menuNameMaxLength'), trigger: 'blur' }
  51 + ],
  52 + url: [
  53 + { max: 100, message: this.$t('convenienceMenus.pagePathMaxLength'), trigger: 'blur' }
  54 + ],
  55 + seq: [
  56 + { required: true, message: this.$t('convenienceMenus.displayOrderRequired'), trigger: 'blur' }
  57 + ],
  58 + remark: [
  59 + { max: 200, message: this.$t('convenienceMenus.remarkMaxLength'), trigger: 'blur' }
  60 + ]
  61 + }
  62 + }
  63 + },
  64 + methods: {
  65 + open() {
  66 + this.visible = true
  67 + },
  68 + handleClose() {
  69 + this.$refs.form.resetFields()
  70 + this.$refs.uploadImage.clear()
  71 + },
  72 + handleImageChange(url) {
  73 + this.form.icon = url
  74 + },
  75 + async handleSubmit() {
  76 + this.$refs.form.validate(async valid => {
  77 + if (valid) {
  78 + try {
  79 + await addConvenienceMenus(this.form)
  80 + this.$message.success(this.$t('common.addSuccess'))
  81 + this.visible = false
  82 + this.$emit('success')
  83 + } catch (error) {
  84 + this.$message.error(error.message)
  85 + }
  86 + }
  87 + })
  88 + }
  89 + }
  90 +}
  91 +</script>
0 92 \ No newline at end of file
... ...
src/components/mall/AddStoreInfo.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('storeInfoManage.common.add')"
  4 + :visible.sync="visible"
  5 + width="50%"
  6 + @close="handleClose"
  7 + >
  8 + <el-form ref="form" :model="form" :rules="rules" label-width="120px">
  9 + <el-form-item
  10 + :label="$t('storeInfoManage.table.storeName')"
  11 + prop="name"
  12 + >
  13 + <el-input
  14 + v-model="form.name"
  15 + :placeholder="$t('storeInfoManage.search.storeName')"
  16 + />
  17 + </el-form-item>
  18 + <el-form-item
  19 + :label="$t('storeInfoManage.table.convenienceType')"
  20 + prop="convenienceMenusId"
  21 + >
  22 + <el-select
  23 + v-model="form.convenienceMenusId"
  24 + :placeholder="$t('storeInfoManage.search.convenienceType')"
  25 + style="width: 100%"
  26 + >
  27 + <el-option
  28 + v-for="item in menuInfos"
  29 + :key="item.convenienceMenusId"
  30 + :label="item.name"
  31 + :value="item.convenienceMenusId"
  32 + />
  33 + </el-select>
  34 + </el-form-item>
  35 + <el-form-item
  36 + :label="$t('storeInfoManage.table.isShow')"
  37 + prop="isShow"
  38 + >
  39 + <el-select
  40 + v-model="form.isShow"
  41 + :placeholder="$t('storeInfoManage.search.isShow')"
  42 + style="width: 100%"
  43 + >
  44 + <el-option
  45 + :label="$t('storeInfoManage.common.yes')"
  46 + value="Y"
  47 + />
  48 + <el-option
  49 + :label="$t('storeInfoManage.common.no')"
  50 + value="N"
  51 + />
  52 + </el-select>
  53 + </el-form-item>
  54 + <el-form-item
  55 + :label="$t('storeInfoManage.table.icon')"
  56 + prop="icon"
  57 + >
  58 + <upload-image
  59 + ref="uploadImage"
  60 + :image-count="1"
  61 + @change="handleImageChange"
  62 + />
  63 + </el-form-item>
  64 + <el-form-item
  65 + :label="$t('storeInfoManage.table.tel')"
  66 + prop="tel"
  67 + >
  68 + <el-input
  69 + v-model="form.tel"
  70 + :placeholder="$t('storeInfoManage.search.storeName')"
  71 + />
  72 + </el-form-item>
  73 + <el-form-item
  74 + :label="$t('storeInfoManage.table.site')"
  75 + prop="site"
  76 + >
  77 + <el-input
  78 + v-model="form.site"
  79 + :placeholder="$t('storeInfoManage.search.storeName')"
  80 + />
  81 + </el-form-item>
  82 + <el-form-item
  83 + :label="$t('storeInfoManage.table.seq')"
  84 + prop="seq"
  85 + >
  86 + <el-input
  87 + v-model="form.seq"
  88 + :placeholder="$t('storeInfoManage.search.storeName')"
  89 + />
  90 + </el-form-item>
  91 + <el-form-item
  92 + :label="$t('storeInfoManage.table.workTime')"
  93 + prop="workTime"
  94 + >
  95 + <el-input
  96 + v-model="form.workTime"
  97 + :placeholder="$t('storeInfoManage.search.storeName')"
  98 + />
  99 + </el-form-item>
  100 + <el-form-item
  101 + :label="$t('storeInfoManage.table.remark')"
  102 + prop="remark"
  103 + >
  104 + <el-input
  105 + v-model="form.remark"
  106 + type="textarea"
  107 + :rows="4"
  108 + :placeholder="$t('storeInfoManage.search.storeName')"
  109 + />
  110 + </el-form-item>
  111 + </el-form>
  112 + <span slot="footer" class="dialog-footer">
  113 + <el-button @click="handleClose">
  114 + {{ $t('storeInfoManage.common.cancel') }}
  115 + </el-button>
  116 + <el-button type="primary" @click="handleSubmit">
  117 + {{ $t('storeInfoManage.common.save') }}
  118 + </el-button>
  119 + </span>
  120 + </el-dialog>
  121 +</template>
  122 +
  123 +<script>
  124 +import { saveStoreInfo } from '@/api/mall/storeInfoManageApi'
  125 +import UploadImage from '@/components/mall/UploadImage'
  126 +
  127 +export default {
  128 + name: 'AddStoreInfo',
  129 + components: {
  130 + UploadImage
  131 + },
  132 + props: {
  133 + menuInfos: {
  134 + type: Array,
  135 + default: () => []
  136 + }
  137 + },
  138 + data() {
  139 + return {
  140 + visible: false,
  141 + form: {
  142 + name: '',
  143 + convenienceMenusId: '',
  144 + isShow: '',
  145 + icon: '',
  146 + tel: '',
  147 + site: '',
  148 + seq: '',
  149 + workTime: '',
  150 + remark: ''
  151 + },
  152 + rules: {
  153 + name: [
  154 + { required: true, message: this.$t('storeInfoManage.search.storeName'), trigger: 'blur' },
  155 + { max: 50, message: this.$t('storeInfoManage.error.maxLength50'), trigger: 'blur' }
  156 + ],
  157 + tel: [
  158 + { max: 13, message: this.$t('storeInfoManage.error.maxLength13'), trigger: 'blur' }
  159 + ],
  160 + site: [
  161 + { max: 100, message: this.$t('storeInfoManage.error.maxLength100'), trigger: 'blur' }
  162 + ],
  163 + seq: [
  164 + { required: true, message: this.$t('storeInfoManage.error.required'), trigger: 'blur' },
  165 + { type: 'number', message: this.$t('storeInfoManage.error.number'), trigger: 'blur' }
  166 + ],
  167 + workTime: [
  168 + { max: 200, message: this.$t('storeInfoManage.error.maxLength200'), trigger: 'blur' }
  169 + ],
  170 + remark: [
  171 + { max: 5000, message: this.$t('storeInfoManage.error.maxLength5000'), trigger: 'blur' }
  172 + ]
  173 + }
  174 + }
  175 + },
  176 + methods: {
  177 + open() {
  178 + this.visible = true
  179 + this.$nextTick(() => {
  180 + this.$refs.form && this.$refs.form.resetFields()
  181 + this.$refs.uploadImage && this.$refs.uploadImage.clear()
  182 + })
  183 + },
  184 + handleClose() {
  185 + this.visible = false
  186 + this.$emit('close')
  187 + },
  188 + handleImageChange(images) {
  189 + this.form.icon = images.length > 0 ? images[0] : ''
  190 + },
  191 + async handleSubmit() {
  192 + try {
  193 + await this.$refs.form.validate()
  194 + const formData = { ...this.form }
  195 + if (formData.seq) {
  196 + formData.seq = Number(formData.seq)
  197 + }
  198 +
  199 + await saveStoreInfo(formData)
  200 + this.$message.success(this.$t('storeInfoManage.common.saveSuccess'))
  201 + this.$emit('success')
  202 + this.handleClose()
  203 + } catch (error) {
  204 + if (error !== 'validate') {
  205 + this.$message.error(error.message || this.$t('storeInfoManage.error.saveFailed'))
  206 + }
  207 + }
  208 + }
  209 + }
  210 +}
  211 +</script>
0 212 \ No newline at end of file
... ...
src/components/mall/DeleteConvenienceMenus.vue 0 → 100644
  1 +<template>
  2 + <el-dialog :title="$t('common.deleteConfirm')" :visible.sync="visible" width="30%" @close="handleClose">
  3 + <p>{{ $t('convenienceMenus.deleteConfirm') }}</p>
  4 + <span slot="footer" class="dialog-footer">
  5 + <el-button @click="visible = false">{{ $t('common.cancel') }}</el-button>
  6 + <el-button type="primary" @click="handleConfirm">{{ $t('common.confirm') }}</el-button>
  7 + </span>
  8 + </el-dialog>
  9 +</template>
  10 +
  11 +<script>
  12 +import { deleteConvenienceMenus } from '@/api/mall/convenienceMenusManageApi'
  13 +
  14 +export default {
  15 + name: 'DeleteConvenienceMenus',
  16 + data() {
  17 + return {
  18 + visible: false,
  19 + convenienceMenusId: ''
  20 + }
  21 + },
  22 + methods: {
  23 + open(row) {
  24 + this.convenienceMenusId = row.convenienceMenusId
  25 + this.visible = true
  26 + },
  27 + handleClose() {
  28 + this.convenienceMenusId = ''
  29 + },
  30 + async handleConfirm() {
  31 + try {
  32 + await deleteConvenienceMenus({ convenienceMenusId: this.convenienceMenusId })
  33 + this.$message.success(this.$t('common.deleteSuccess'))
  34 + this.visible = false
  35 + this.$emit('success')
  36 + } catch (error) {
  37 + this.$message.error(error.message)
  38 + }
  39 + }
  40 + }
  41 +}
  42 +</script>
0 43 \ No newline at end of file
... ...
src/components/mall/DeleteStoreInfo.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('storeInfoManage.common.confirm')"
  4 + :visible.sync="visible"
  5 + width="30%"
  6 + >
  7 + <div>
  8 + {{ $t('storeInfoManage.delete.confirmDelete') }} {{ storeInfo.name }}?
  9 + </div>
  10 + <span slot="footer" class="dialog-footer">
  11 + <el-button @click="visible = false">
  12 + {{ $t('storeInfoManage.common.cancel') }}
  13 + </el-button>
  14 + <el-button type="primary" @click="handleConfirm">
  15 + {{ $t('storeInfoManage.common.confirm') }}
  16 + </el-button>
  17 + </span>
  18 + </el-dialog>
  19 +</template>
  20 +
  21 +<script>
  22 +import { deleteStoreInfo } from '@/api/mall/storeInfoManageApi'
  23 +
  24 +export default {
  25 + name: 'DeleteStoreInfo',
  26 + props: {
  27 + storeInfo: {
  28 + type: Object,
  29 + default: () => ({})
  30 + }
  31 + },
  32 + data() {
  33 + return {
  34 + visible: false
  35 + }
  36 + },
  37 + methods: {
  38 + open() {
  39 + this.visible = true
  40 + },
  41 + async handleConfirm() {
  42 + try {
  43 + await deleteStoreInfo({ storeInfoId: this.storeInfo.storeInfoId })
  44 + this.$message.success(this.$t('storeInfoManage.common.deleteSuccess'))
  45 + this.visible = false
  46 + this.$emit('success')
  47 + } catch (error) {
  48 + this.$message.error(error.message || this.$t('storeInfoManage.error.deleteFailed'))
  49 + }
  50 + }
  51 + }
  52 +}
  53 +</script>
0 54 \ No newline at end of file
... ...
src/components/mall/EditStoreInfo.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('storeInfoManage.common.edit')"
  4 + :visible.sync="visible"
  5 + width="50%"
  6 + @close="handleClose"
  7 + >
  8 + <el-form ref="form" :model="form" :rules="rules" label-width="120px">
  9 + <el-form-item
  10 + :label="$t('storeInfoManage.table.storeName')"
  11 + prop="name"
  12 + >
  13 + <el-input
  14 + v-model="form.name"
  15 + :placeholder="$t('storeInfoManage.search.storeName')"
  16 + />
  17 + </el-form-item>
  18 + <el-form-item
  19 + :label="$t('storeInfoManage.table.convenienceType')"
  20 + prop="convenienceMenusId"
  21 + >
  22 + <el-select
  23 + v-model="form.convenienceMenusId"
  24 + :placeholder="$t('storeInfoManage.search.convenienceType')"
  25 + style="width: 100%"
  26 + >
  27 + <el-option
  28 + v-for="item in menuInfos"
  29 + :key="item.convenienceMenusId"
  30 + :label="item.name"
  31 + :value="item.convenienceMenusId"
  32 + />
  33 + </el-select>
  34 + </el-form-item>
  35 + <el-form-item
  36 + :label="$t('storeInfoManage.table.isShow')"
  37 + prop="isShow"
  38 + >
  39 + <el-select
  40 + v-model="form.isShow"
  41 + :placeholder="$t('storeInfoManage.search.isShow')"
  42 + style="width: 100%"
  43 + >
  44 + <el-option
  45 + :label="$t('storeInfoManage.common.yes')"
  46 + value="Y"
  47 + />
  48 + <el-option
  49 + :label="$t('storeInfoManage.common.no')"
  50 + value="N"
  51 + />
  52 + </el-select>
  53 + </el-form-item>
  54 + <el-form-item
  55 + :label="$t('storeInfoManage.table.icon')"
  56 + prop="icon"
  57 + >
  58 + <upload-image
  59 + ref="uploadImage"
  60 + :image-count="1"
  61 + :initial-images="[form.icon]"
  62 + @change="handleImageChange"
  63 + />
  64 + </el-form-item>
  65 + <el-form-item
  66 + :label="$t('storeInfoManage.table.tel')"
  67 + prop="tel"
  68 + >
  69 + <el-input
  70 + v-model="form.tel"
  71 + :placeholder="$t('storeInfoManage.search.storeName')"
  72 + />
  73 + </el-form-item>
  74 + <el-form-item
  75 + :label="$t('storeInfoManage.table.site')"
  76 + prop="site"
  77 + >
  78 + <el-input
  79 + v-model="form.site"
  80 + :placeholder="$t('storeInfoManage.search.storeName')"
  81 + />
  82 + </el-form-item>
  83 + <el-form-item
  84 + :label="$t('storeInfoManage.table.seq')"
  85 + prop="seq"
  86 + >
  87 + <el-input
  88 + v-model="form.seq"
  89 + :placeholder="$t('storeInfoManage.search.storeName')"
  90 + />
  91 + </el-form-item>
  92 + <el-form-item
  93 + :label="$t('storeInfoManage.table.workTime')"
  94 + prop="workTime"
  95 + >
  96 + <el-input
  97 + v-model="form.workTime"
  98 + :placeholder="$t('storeInfoManage.search.storeName')"
  99 + />
  100 + </el-form-item>
  101 + <el-form-item
  102 + :label="$t('storeInfoManage.table.remark')"
  103 + prop="remark"
  104 + >
  105 + <el-input
  106 + v-model="form.remark"
  107 + type="textarea"
  108 + :rows="4"
  109 + :placeholder="$t('storeInfoManage.search.storeName')"
  110 + />
  111 + </el-form-item>
  112 + </el-form>
  113 + <span slot="footer" class="dialog-footer">
  114 + <el-button @click="handleClose">
  115 + {{ $t('storeInfoManage.common.cancel') }}
  116 + </el-button>
  117 + <el-button type="primary" @click="handleSubmit">
  118 + {{ $t('storeInfoManage.common.save') }}
  119 + </el-button>
  120 + </span>
  121 + </el-dialog>
  122 +</template>
  123 +
  124 +<script>
  125 +import { updateStoreInfo } from '@/api/mall/storeInfoManageApi'
  126 +import UploadImage from '@/components/mall/UploadImage'
  127 +
  128 +export default {
  129 + name: 'EditStoreInfo',
  130 + components: {
  131 + UploadImage
  132 + },
  133 + props: {
  134 + storeInfo: {
  135 + type: Object,
  136 + default: () => ({})
  137 + },
  138 + menuInfos: {
  139 + type: Array,
  140 + default: () => []
  141 + }
  142 + },
  143 + data() {
  144 + return {
  145 + visible: false,
  146 + form: {
  147 + storeInfoId: '',
  148 + name: '',
  149 + convenienceMenusId: '',
  150 + isShow: '',
  151 + icon: '',
  152 + tel: '',
  153 + site: '',
  154 + seq: '',
  155 + workTime: '',
  156 + remark: ''
  157 + },
  158 + rules: {
  159 + name: [
  160 + { required: true, message: this.$t('storeInfoManage.search.storeName'), trigger: 'blur' },
  161 + { max: 50, message: this.$t('storeInfoManage.error.maxLength50'), trigger: 'blur' }
  162 + ],
  163 + tel: [
  164 + { max: 13, message: this.$t('storeInfoManage.error.maxLength13'), trigger: 'blur' }
  165 + ],
  166 + site: [
  167 + { max: 100, message: this.$t('storeInfoManage.error.maxLength100'), trigger: 'blur' }
  168 + ],
  169 + seq: [
  170 + { required: true, message: this.$t('storeInfoManage.error.required'), trigger: 'blur' },
  171 + { type: 'number', message: this.$t('storeInfoManage.error.number'), trigger: 'blur' }
  172 + ],
  173 + workTime: [
  174 + { max: 200, message: this.$t('storeInfoManage.error.maxLength200'), trigger: 'blur' }
  175 + ],
  176 + remark: [
  177 + { max: 5000, message: this.$t('storeInfoManage.error.maxLength5000'), trigger: 'blur' }
  178 + ],
  179 + storeInfoId: [
  180 + { required: true, message: this.$t('storeInfoManage.error.required'), trigger: 'blur' }
  181 + ]
  182 + }
  183 + }
  184 + },
  185 + watch: {
  186 + storeInfo: {
  187 + immediate: true,
  188 + handler(val) {
  189 + if (val) {
  190 + this.form = { ...val }
  191 + }
  192 + }
  193 + }
  194 + },
  195 + methods: {
  196 + open() {
  197 + this.visible = true
  198 + },
  199 + handleClose() {
  200 + this.visible = false
  201 + this.$emit('close')
  202 + },
  203 + handleImageChange(images) {
  204 + this.form.icon = images.length > 0 ? images[0] : ''
  205 + },
  206 + async handleSubmit() {
  207 + try {
  208 + await this.$refs.form.validate()
  209 + const formData = { ...this.form }
  210 + if (formData.seq) {
  211 + formData.seq = Number(formData.seq)
  212 + }
  213 +
  214 + await updateStoreInfo(formData)
  215 + this.$message.success(this.$t('storeInfoManage.common.updateSuccess'))
  216 + this.$emit('success')
  217 + this.handleClose()
  218 + } catch (error) {
  219 + if (error !== 'validate') {
  220 + this.$message.error(error.message || this.$t('storeInfoManage.error.updateFailed'))
  221 + }
  222 + }
  223 + }
  224 + }
  225 +}
  226 +</script>
0 227 \ No newline at end of file
... ...
src/components/mall/UploadImage.vue 0 → 100644
  1 +<template>
  2 + <div class="upload-image-container">
  3 + <div v-for="(image, index) in images" :key="index" class="image-item">
  4 + <el-image
  5 + :src="image"
  6 + fit="cover"
  7 + style="width: 100px; height: 100px;"
  8 + :preview-src-list="[image]"
  9 + ></el-image>
  10 + <i class="el-icon-delete" @click="removeImage(index)"></i>
  11 + </div>
  12 + <el-upload
  13 + v-if="images.length < maxCount"
  14 + action=""
  15 + :show-file-list="false"
  16 + :before-upload="beforeUpload"
  17 + :http-request="handleUpload"
  18 + >
  19 + <div class="upload-btn">
  20 + <i class="el-icon-plus"></i>
  21 + </div>
  22 + </el-upload>
  23 + </div>
  24 +</template>
  25 +
  26 +<script>
  27 +import { uploadFile } from '@/api/mall/convenienceMenusManageApi'
  28 +
  29 +export default {
  30 + name: 'UploadImage',
  31 + props: {
  32 + maxCount: {
  33 + type: Number,
  34 + default: 1
  35 + }
  36 + },
  37 + data() {
  38 + return {
  39 + images: []
  40 + }
  41 + },
  42 + methods: {
  43 + beforeUpload(file) {
  44 + const isImage = file.type.includes('image/')
  45 + const isLt2M = file.size / 1024 / 1024 < 2
  46 +
  47 + if (!isImage) {
  48 + this.$message.error(this.$t('upload.imageTypeError'))
  49 + }
  50 + if (!isLt2M) {
  51 + this.$message.error(this.$t('upload.imageSizeError'))
  52 + }
  53 + return isImage && isLt2M
  54 + },
  55 + async handleUpload({ file }) {
  56 + try {
  57 + const formData = new FormData()
  58 + formData.append('uploadFile', file)
  59 + const { url } = await uploadFile(formData)
  60 + this.images.push(url)
  61 + this.$emit('change', url)
  62 + } catch (error) {
  63 + this.$message.error(error.message)
  64 + }
  65 + },
  66 + removeImage(index) {
  67 + this.images.splice(index, 1)
  68 + this.$emit('change', this.images[0] || '')
  69 + },
  70 + clear() {
  71 + this.images = []
  72 + this.$emit('change', '')
  73 + }
  74 + }
  75 +}
  76 +</script>
  77 +
  78 +<style lang="scss" scoped>
  79 +.upload-image-container {
  80 + display: flex;
  81 + flex-wrap: wrap;
  82 + gap: 10px;
  83 +
  84 + .image-item {
  85 + position: relative;
  86 +
  87 + .el-icon-delete {
  88 + position: absolute;
  89 + top: 5px;
  90 + right: 5px;
  91 + color: #f56c6c;
  92 + cursor: pointer;
  93 + font-size: 16px;
  94 + background: rgba(255, 255, 255, 0.7);
  95 + border-radius: 50%;
  96 + padding: 5px;
  97 + }
  98 + }
  99 +
  100 + .upload-btn {
  101 + width: 100px;
  102 + height: 100px;
  103 + display: flex;
  104 + justify-content: center;
  105 + align-items: center;
  106 + border: 1px dashed #d9d9d9;
  107 + border-radius: 6px;
  108 + cursor: pointer;
  109 + background-color: #fbfdff;
  110 +
  111 + &:hover {
  112 + border-color: #409eff;
  113 + }
  114 +
  115 + i {
  116 + font-size: 28px;
  117 + color: #8c939d;
  118 + }
  119 + }
  120 +}
  121 +</style>
0 122 \ No newline at end of file
... ...
src/i18n/index.js
... ... @@ -103,6 +103,8 @@ import { messages as marketRuleMessages } from &#39;../views/market/marketRuleLang&#39;
103 103 import { messages as marketBlacklistManageMessages } from '../views/market/marketBlacklistManageLang'
104 104 import { messages as marketLogMessages } from '../views/market/marketLogLang'
105 105 import { messages as advertManageMessages } from '../views/admin/advertManageLang'
  106 +import { messages as convenienceMenusManageMessages } from '../views/mall/convenienceMenusManageLang'
  107 +import { messages as storeInfoManageMessages } from '../views/mall/storeInfoManageLang'
106 108  
107 109 Vue.use(VueI18n)
108 110  
... ... @@ -210,6 +212,8 @@ const messages = {
210 212 ...marketBlacklistManageMessages.en,
211 213 ...marketLogMessages.en,
212 214 ...advertManageMessages.en,
  215 + ...convenienceMenusManageMessages.en,
  216 + ...storeInfoManageMessages.en,
213 217 },
214 218 zh: {
215 219 ...loginMessages.zh,
... ... @@ -313,6 +317,8 @@ const messages = {
313 317 ...marketBlacklistManageMessages.zh,
314 318 ...marketLogMessages.zh,
315 319 ...advertManageMessages.zh,
  320 + ...convenienceMenusManageMessages.zh,
  321 + ...storeInfoManageMessages.zh,
316 322 }
317 323 }
318 324  
... ...
src/router/index.js
... ... @@ -501,6 +501,16 @@ const routes = [
501 501 name: '/pages/property/advertManage',
502 502 component: () => import('@/views/admin/advertManageList.vue')
503 503 },
  504 + {
  505 + path:'/pages/admin/convenienceMenusManage',
  506 + name:'/pages/admin/convenienceMenusManage',
  507 + component: () => import('@/views/mall/convenienceMenusManageList.vue')
  508 + },
  509 + {
  510 + path:'/pages/admin/storeInfoManage',
  511 + name:'/pages/admin/storeInfoManage',
  512 + component: () => import('@/views/mall/storeInfoManageList.vue')
  513 + },
504 514 // 其他子路由可以在这里添加
505 515 ]
506 516 },
... ...
src/views/mall/convenienceMenusManageLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + convenienceMenus: {
  4 + title: 'Convenience Services',
  5 + assetId: 'Asset ID',
  6 + menuName: 'Menu Name',
  7 + imageUrl: 'Image URL',
  8 + pagePath: 'Page Path',
  9 + displayOrder: 'Display Order',
  10 + remark: 'Remark',
  11 + fetchError: 'Failed to fetch convenience menus',
  12 + addTitle: 'Add Convenience Menu',
  13 + editTitle: 'Edit Convenience Menu',
  14 + deleteConfirm: 'Are you sure to delete this convenience menu?'
  15 + }
  16 + },
  17 + zh: {
  18 + convenienceMenus: {
  19 + title: '便民服务',
  20 + assetId: '资产ID',
  21 + menuName: '菜单名称',
  22 + imageUrl: '图片地址',
  23 + pagePath: '页面路径',
  24 + displayOrder: '显示序号',
  25 + remark: '备注',
  26 + fetchError: '获取便民服务菜单失败',
  27 + addTitle: '添加便民服务菜单',
  28 + editTitle: '修改便民服务菜单',
  29 + deleteConfirm: '确定删除便民服务菜单吗?'
  30 + }
  31 + }
  32 +}
0 33 \ No newline at end of file
... ...
src/views/mall/convenienceMenusManageList.vue 0 → 100644
  1 +<template>
  2 + <div class="convenience-menus-container">
  3 + <el-card class="box-card">
  4 + <div slot="header" class="clearfix flex justify-between">
  5 + <span>{{ $t('convenienceMenus.title') }}</span>
  6 + <el-button type="primary" size="small" style="float: right" @click="openAddModal">
  7 + <i class="el-icon-plus"></i>
  8 + {{ $t('common.add') }}
  9 + </el-button>
  10 + </div>
  11 +
  12 + <el-table :data="tableData" border style="width: 100%">
  13 + <el-table-column prop="convenienceMenusId" :label="$t('convenienceMenus.assetId')" align="center" />
  14 + <el-table-column prop="name" :label="$t('convenienceMenus.menuName')" align="center" />
  15 + <el-table-column :label="$t('convenienceMenus.imageUrl')" align="center">
  16 + <template slot-scope="scope">
  17 + <el-image style="width: 60px; height: 60px; border-radius: 5px;" :src="scope.row.icon"
  18 + :preview-src-list="[scope.row.icon]" fit="cover"></el-image>
  19 + </template>
  20 + </el-table-column>
  21 + <el-table-column prop="url" :label="$t('convenienceMenus.pagePath')" align="center" />
  22 + <el-table-column prop="seq" :label="$t('convenienceMenus.displayOrder')" align="center" />
  23 + <el-table-column prop="remark" :label="$t('convenienceMenus.remark')" align="center" />
  24 + <el-table-column :label="$t('common.operation')" align="center" width="200">
  25 + <template slot-scope="scope">
  26 + <el-button size="mini" type="danger" @click="openDeleteModal(scope.row)">
  27 + {{ $t('common.delete') }}
  28 + </el-button>
  29 + </template>
  30 + </el-table-column>
  31 + </el-table>
  32 +
  33 + <el-pagination :current-page="pagination.current" :page-sizes="[10, 20, 30, 50]" :page-size="pagination.size"
  34 + :total="pagination.total" layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange"
  35 + @current-change="handleCurrentChange" />
  36 + </el-card>
  37 +
  38 + <add-convenience-menus ref="addModal" @success="fetchData" />
  39 + <delete-convenience-menus ref="deleteModal" @success="fetchData" />
  40 + </div>
  41 +</template>
  42 +
  43 +<script>
  44 +import { getConvenienceMenusList } from '@/api/mall/convenienceMenusManageApi'
  45 +import AddConvenienceMenus from '@/components/mall/AddConvenienceMenus'
  46 +import DeleteConvenienceMenus from '@/components/mall/DeleteConvenienceMenus'
  47 +
  48 +export default {
  49 + name: 'ConvenienceMenusManageList',
  50 + components: {
  51 + AddConvenienceMenus,
  52 + DeleteConvenienceMenus
  53 + },
  54 + data() {
  55 + return {
  56 + tableData: [],
  57 + pagination: {
  58 + current: 1,
  59 + size: 10,
  60 + total: 0
  61 + },
  62 + searchForm: {
  63 + name: ''
  64 + }
  65 + }
  66 + },
  67 + created() {
  68 + this.fetchData()
  69 + },
  70 + methods: {
  71 + async fetchData() {
  72 + try {
  73 + const params = {
  74 + page: this.pagination.current,
  75 + row: this.pagination.size,
  76 + ...this.searchForm
  77 + }
  78 + const { data, total } = await getConvenienceMenusList(params)
  79 + this.tableData = data
  80 + this.pagination.total = total
  81 + } catch (error) {
  82 + this.$message.error(this.$t('convenienceMenus.fetchError'))
  83 + }
  84 + },
  85 + openAddModal() {
  86 + this.$refs.addModal.open()
  87 + },
  88 + openEditModal(row) {
  89 + this.$refs.editModal.open(row)
  90 + },
  91 + openDeleteModal(row) {
  92 + this.$refs.deleteModal.open(row)
  93 + },
  94 + handleSizeChange(val) {
  95 + this.pagination.size = val
  96 + this.fetchData()
  97 + },
  98 + handleCurrentChange(val) {
  99 + this.pagination.current = val
  100 + this.fetchData()
  101 + }
  102 + }
  103 +}
  104 +</script>
  105 +
  106 +<style lang="scss" scoped>
  107 +.convenience-menus-container {
  108 + padding: 20px;
  109 +
  110 + .box-card {
  111 + margin-bottom: 20px;
  112 + }
  113 +
  114 + .el-pagination {
  115 + margin-top: 20px;
  116 + text-align: right;
  117 + }
  118 +}
  119 +</style>
0 120 \ No newline at end of file
... ...
src/views/mall/storeInfoManageLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + storeInfoManage: {
  4 + search: {
  5 + title: 'Search Conditions',
  6 + storeName: 'Please enter store name',
  7 + convenienceType: 'Please select convenience type',
  8 + isShow: 'Please select whether to display'
  9 + },
  10 + list: {
  11 + title: 'Store Information'
  12 + },
  13 + table: {
  14 + storeInfoId: 'Store ID',
  15 + storeName: 'Store Name',
  16 + icon: 'Image URL',
  17 + tel: 'Store Phone',
  18 + site: 'Store Location',
  19 + seq: 'Display Sequence',
  20 + isShow: 'Is Show',
  21 + convenienceType: 'Convenience Type',
  22 + workTime: 'Work Time',
  23 + remark: 'Remark'
  24 + },
  25 + common: {
  26 + search: 'Search',
  27 + add: 'Add',
  28 + edit: 'Edit',
  29 + delete: 'Delete',
  30 + yes: 'Yes',
  31 + no: 'No',
  32 + operation: 'Operation',
  33 + cancel: 'Cancel',
  34 + save: 'Save',
  35 + confirm: 'Confirm',
  36 + saveSuccess: 'Save successfully',
  37 + updateSuccess: 'Update successfully',
  38 + deleteSuccess: 'Delete successfully',
  39 + required: 'Required',
  40 + optional: 'Optional'
  41 + },
  42 + delete: {
  43 + confirmDelete: 'Are you sure to delete store info'
  44 + },
  45 + error: {
  46 + fetchStoreInfoFailed: 'Failed to get store information',
  47 + fetchConvenienceMenusFailed: 'Failed to get convenience menus',
  48 + saveFailed: 'Failed to save store info',
  49 + updateFailed: 'Failed to update store info',
  50 + deleteFailed: 'Failed to delete store info',
  51 + uploadFailed: 'Failed to upload image',
  52 + uploadImageOnly: 'Only image files can be uploaded',
  53 + imageSizeLimit: 'Image size cannot exceed 2MB',
  54 + maxLength50: 'Cannot exceed 50 characters',
  55 + maxLength13: 'Cannot exceed 13 characters',
  56 + maxLength100: 'Cannot exceed 100 characters',
  57 + maxLength200: 'Cannot exceed 200 characters',
  58 + maxLength5000: 'Cannot exceed 5000 characters',
  59 + required: 'This field is required',
  60 + number: 'Please enter a valid number'
  61 + },
  62 + validation: {
  63 + storeNameRequired: 'Store name is required',
  64 + seqRequired: 'Display sequence is required',
  65 + seqNumber: 'Display sequence must be a number',
  66 + telMaxLength: 'Phone number cannot exceed 13 characters',
  67 + siteMaxLength: 'Location cannot exceed 100 characters',
  68 + workTimeMaxLength: 'Work time cannot exceed 200 characters',
  69 + remarkMaxLength: 'Remark cannot exceed 5000 characters'
  70 + }
  71 + }
  72 + },
  73 + zh: {
  74 + storeInfoManage: {
  75 + search: {
  76 + title: '查询条件',
  77 + storeName: '请输入商户名称',
  78 + convenienceType: '请选择便民种类',
  79 + isShow: '请选择是否显示'
  80 + },
  81 + list: {
  82 + title: '商户信息'
  83 + },
  84 + table: {
  85 + storeInfoId: '商户信息ID',
  86 + storeName: '商户名称',
  87 + icon: '图片地址',
  88 + tel: '商户电话',
  89 + site: '商户位置',
  90 + seq: '显示序号',
  91 + isShow: '是否显示',
  92 + convenienceType: '便民类型',
  93 + workTime: '工作时间',
  94 + remark: '备注'
  95 + },
  96 + common: {
  97 + search: '查询',
  98 + add: '添加',
  99 + edit: '修改',
  100 + delete: '删除',
  101 + yes: '是',
  102 + no: '否',
  103 + operation: '操作',
  104 + cancel: '取消',
  105 + save: '保存',
  106 + confirm: '确认',
  107 + saveSuccess: '保存成功',
  108 + updateSuccess: '更新成功',
  109 + deleteSuccess: '删除成功',
  110 + required: '必填',
  111 + optional: '选填'
  112 + },
  113 + delete: {
  114 + confirmDelete: '确定删除商户信息'
  115 + },
  116 + error: {
  117 + fetchStoreInfoFailed: '获取商户信息失败',
  118 + fetchConvenienceMenusFailed: '获取便民菜单失败',
  119 + saveFailed: '保存商户信息失败',
  120 + updateFailed: '更新商户信息失败',
  121 + deleteFailed: '删除商户信息失败',
  122 + uploadFailed: '上传图片失败',
  123 + uploadImageOnly: '只能上传图片文件',
  124 + imageSizeLimit: '图片大小不能超过2MB',
  125 + maxLength50: '不能超过50个字符',
  126 + maxLength13: '不能超过13个字符',
  127 + maxLength100: '不能超过100个字符',
  128 + maxLength200: '不能超过200个字符',
  129 + maxLength5000: '不能超过5000个字符',
  130 + required: '此字段为必填项',
  131 + number: '请输入有效的数字'
  132 + },
  133 + validation: {
  134 + storeNameRequired: '商户名称为必填项',
  135 + seqRequired: '显示序号为必填项',
  136 + seqNumber: '显示序号必须为数字',
  137 + telMaxLength: '电话号码不能超过13个字符',
  138 + siteMaxLength: '位置不能超过100个字符',
  139 + workTimeMaxLength: '工作时间不能超过200个字符',
  140 + remarkMaxLength: '备注不能超过5000个字符'
  141 + }
  142 + }
  143 + }
  144 +}
0 145 \ No newline at end of file
... ...
src/views/mall/storeInfoManageList.vue 0 → 100644
  1 +<template>
  2 + <div class="store-info-manage-container">
  3 + <!-- 查询条件 -->
  4 + <el-card v-if="componentShow === 'storeInfoManage'" class="search-wrapper">
  5 + <div slot="header" class="clearfix text-left">
  6 + <span>{{ $t('storeInfoManage.search.title') }}</span>
  7 + </div>
  8 + <el-row :gutter="20">
  9 + <el-col :span="6">
  10 + <el-input v-model="conditions.name" :placeholder="$t('storeInfoManage.search.storeName')" clearable />
  11 + </el-col>
  12 + <el-col :span="6">
  13 + <el-select v-model="conditions.convenienceMenusId" :placeholder="$t('storeInfoManage.search.convenienceType')"
  14 + clearable>
  15 + <el-option v-for="item in menuInfos" :key="item.convenienceMenusId" :label="item.name"
  16 + :value="item.convenienceMenusId" />
  17 + </el-select>
  18 + </el-col>
  19 + <el-col :span="6">
  20 + <el-select v-model="conditions.isShow" :placeholder="$t('storeInfoManage.search.isShow')" clearable>
  21 + <el-option :label="$t('storeInfoManage.common.yes')" value="Y" />
  22 + <el-option :label="$t('storeInfoManage.common.no')" value="N" />
  23 + </el-select>
  24 + </el-col>
  25 + <el-col :span="6">
  26 + <el-button type="primary" @click="handleQuery">
  27 + <i class="el-icon-search"></i>
  28 + {{ $t('storeInfoManage.common.search') }}
  29 + </el-button>
  30 + </el-col>
  31 + </el-row>
  32 + </el-card>
  33 +
  34 + <!-- 商户信息列表 -->
  35 + <el-card v-if="componentShow === 'storeInfoManage'" class="list-wrapper">
  36 + <div slot="header" class="clearfix flex justify-between">
  37 + <span>{{ $t('storeInfoManage.list.title') }}</span>
  38 + <el-button type="primary" size="small" style="float: right;" @click="handleAdd">
  39 + <i class="el-icon-plus"></i>
  40 + {{ $t('storeInfoManage.common.add') }}
  41 + </el-button>
  42 + </div>
  43 + <el-table v-loading="loading" :data="storeInfos" border style="width: 100%">
  44 + <el-table-column prop="storeInfoId" :label="$t('storeInfoManage.table.storeInfoId')" align="center" />
  45 + <el-table-column prop="name" :label="$t('storeInfoManage.table.storeName')" align="center" />
  46 + <el-table-column :label="$t('storeInfoManage.table.icon')" align="center">
  47 + <template slot-scope="scope">
  48 + <el-image style="width: 60px; height: 60px; border-radius: 5px;" :src="scope.row.icon"
  49 + :preview-src-list="[scope.row.icon]" fit="cover" />
  50 + </template>
  51 + </el-table-column>
  52 + <el-table-column prop="tel" :label="$t('storeInfoManage.table.tel')" align="center" />
  53 + <el-table-column prop="site" :label="$t('storeInfoManage.table.site')" align="center" />
  54 + <el-table-column prop="seq" :label="$t('storeInfoManage.table.seq')" align="center" />
  55 + <el-table-column :label="$t('storeInfoManage.table.isShow')" align="center">
  56 + <template slot-scope="scope">
  57 + {{ scope.row.isShow === 'Y' ? $t('storeInfoManage.common.yes') : $t('storeInfoManage.common.no') }}
  58 + </template>
  59 + </el-table-column>
  60 + <el-table-column :label="$t('storeInfoManage.common.operation')" align="center" width="200">
  61 + <template slot-scope="scope">
  62 + <el-button size="mini" type="primary" @click="handleEdit(scope.row)">
  63 + {{ $t('storeInfoManage.common.edit') }}
  64 + </el-button>
  65 + <el-button size="mini" type="danger" @click="handleDelete(scope.row)">
  66 + {{ $t('storeInfoManage.common.delete') }}
  67 + </el-button>
  68 + </template>
  69 + </el-table-column>
  70 + </el-table>
  71 + <el-pagination :current-page.sync="page.current" :page-sizes="[10, 20, 30, 50]" :page-size="page.size"
  72 + :total="page.total" layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange"
  73 + @current-change="handleCurrentChange" />
  74 + </el-card>
  75 +
  76 + <!-- 子组件 -->
  77 + <add-store-info v-if="componentShow === 'addStoreInfo'" ref="addStoreInfo" @success="handleSuccess"
  78 + @close="handleClose" />
  79 + <edit-store-info v-if="componentShow === 'editStoreInfo'" ref="editStoreInfo" :store-info="currentStoreInfo"
  80 + @success="handleSuccess" @close="handleClose" />
  81 + <delete-store-info ref="deleteStoreInfo" :store-info="currentStoreInfo" @success="handleSuccess" />
  82 + </div>
  83 +</template>
  84 +
  85 +<script>
  86 +import { queryStoreInfo, queryConvenienceMenus } from '@/api/mall/storeInfoManageApi'
  87 +import AddStoreInfo from '@/components/mall/AddStoreInfo'
  88 +import EditStoreInfo from '@/components/mall/EditStoreInfo'
  89 +import DeleteStoreInfo from '@/components/mall/DeleteStoreInfo'
  90 +
  91 +export default {
  92 + name: 'StoreInfoManageList',
  93 + components: {
  94 + AddStoreInfo,
  95 + EditStoreInfo,
  96 + DeleteStoreInfo
  97 + },
  98 + data() {
  99 + return {
  100 + loading: false,
  101 + componentShow: 'storeInfoManage',
  102 + conditions: {
  103 + name: '',
  104 + isShow: '',
  105 + convenienceMenusId: ''
  106 + },
  107 + storeInfos: [],
  108 + menuInfos: [],
  109 + currentStoreInfo: {},
  110 + page: {
  111 + current: 1,
  112 + size: 10,
  113 + total: 0
  114 + }
  115 + }
  116 + },
  117 + created() {
  118 + this.getStoreInfoList()
  119 + this.getConvenienceMenusList()
  120 + },
  121 + methods: {
  122 + async getStoreInfoList() {
  123 + try {
  124 + this.loading = true
  125 + const params = {
  126 + page: this.page.current,
  127 + row: this.page.size,
  128 + ...this.conditions
  129 + }
  130 + const { data, total } = await queryStoreInfo(params)
  131 + this.storeInfos = data
  132 + this.page.total = total
  133 + } catch (error) {
  134 + this.$message.error(this.$t('storeInfoManage.error.fetchStoreInfoFailed'))
  135 + } finally {
  136 + this.loading = false
  137 + }
  138 + },
  139 + async getConvenienceMenusList() {
  140 + try {
  141 + const params = {
  142 + page: 1,
  143 + row: 50
  144 + }
  145 + const { data } = await queryConvenienceMenus(params)
  146 + this.menuInfos = data
  147 + } catch (error) {
  148 + this.$message.error(this.$t('storeInfoManage.error.fetchConvenienceMenusFailed'))
  149 + }
  150 + },
  151 + handleQuery() {
  152 + this.page.current = 1
  153 + this.getStoreInfoList()
  154 + },
  155 + handleAdd() {
  156 + this.componentShow = 'addStoreInfo'
  157 + this.$nextTick(() => {
  158 + this.$refs.addStoreInfo.open()
  159 + })
  160 + },
  161 + handleEdit(row) {
  162 + this.componentShow = 'editStoreInfo'
  163 + this.currentStoreInfo = { ...row }
  164 + this.$nextTick(() => {
  165 + this.$refs.editStoreInfo.open()
  166 + })
  167 + },
  168 + handleDelete(row) {
  169 + this.currentStoreInfo = { ...row }
  170 + this.$nextTick(() => {
  171 + this.$refs.deleteStoreInfo.open()
  172 + })
  173 + },
  174 + handleSuccess() {
  175 + this.componentShow = 'storeInfoManage'
  176 + this.getStoreInfoList()
  177 + },
  178 + handleClose() {
  179 + this.componentShow = 'storeInfoManage'
  180 + },
  181 + handleSizeChange(val) {
  182 + this.page.size = val
  183 + this.getStoreInfoList()
  184 + },
  185 + handleCurrentChange(val) {
  186 + this.page.current = val
  187 + this.getStoreInfoList()
  188 + }
  189 + }
  190 +}
  191 +</script>
  192 +
  193 +<style lang="scss" scoped>
  194 +.store-info-manage-container {
  195 + padding: 20px;
  196 +
  197 + .search-wrapper {
  198 + margin-bottom: 20px;
  199 +
  200 + .el-select {
  201 + width: 100%;
  202 + }
  203 + }
  204 +
  205 + .list-wrapper {
  206 + margin-bottom: 20px;
  207 + }
  208 +
  209 + .el-pagination {
  210 + margin-top: 20px;
  211 + text-align: right;
  212 + }
  213 +}
  214 +</style>
0 215 \ No newline at end of file
... ...