Commit 5c5dc3cdfd5b12e8f2e6322ed4cfb5940db7ae7a

Authored by wuxw
1 parent 2803cb18

开发完成营销广告功能

src/api/admin/advertManageApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 获取广告列表
  4 +export function listAdverts(params) {
  5 + return new Promise((resolve, reject) => {
  6 + request({
  7 + url: '/advert.listAdverts',
  8 + method: 'get',
  9 + params
  10 + }).then(response => {
  11 + const res = response.data
  12 + resolve({
  13 + data: res.adverts,
  14 + total: res.total
  15 + })
  16 + }).catch(error => {
  17 + reject(error)
  18 + })
  19 + })
  20 +}
  21 +
  22 +// 添加广告
  23 +export function saveAdvert(data) {
  24 + return new Promise((resolve, reject) => {
  25 + request({
  26 + url: '/advert.saveAdvert',
  27 + method: 'post',
  28 + data
  29 + }).then(response => {
  30 + const res = response.data
  31 + if (res.code === 0) {
  32 + resolve(res)
  33 + } else {
  34 + reject(new Error(res.msg || 'Failed to save advertisement'))
  35 + }
  36 + }).catch(error => {
  37 + reject(error)
  38 + })
  39 + })
  40 +}
  41 +
  42 +// 更新广告
  43 +export function updateAdvert(data) {
  44 + return new Promise((resolve, reject) => {
  45 + request({
  46 + url: '/advert.updateAdvert',
  47 + method: 'post',
  48 + data
  49 + }).then(response => {
  50 + const res = response.data
  51 + if (res.code === 0) {
  52 + resolve(res)
  53 + } else {
  54 + reject(new Error(res.msg || 'Failed to update advertisement'))
  55 + }
  56 + }).catch(error => {
  57 + reject(error)
  58 + })
  59 + })
  60 +}
  61 +
  62 +// 删除广告
  63 +export function deleteAdvert(advertId) {
  64 + return new Promise((resolve, reject) => {
  65 + request({
  66 + url: '/advert.deleteAdvert',
  67 + method: 'post',
  68 + data: { advertId }
  69 + }).then(response => {
  70 + const res = response.data
  71 + if (res.code === 0) {
  72 + resolve(res)
  73 + } else {
  74 + reject(new Error(res.msg || 'Failed to delete advertisement'))
  75 + }
  76 + }).catch(error => {
  77 + reject(error)
  78 + })
  79 + })
  80 +}
  81 +
  82 +// 上传文件
  83 +export function uploadFile(data) {
  84 + return new Promise((resolve, reject) => {
  85 + request({
  86 + url: '/uploadFile',
  87 + method: 'post',
  88 + data,
  89 + headers: {
  90 + 'Content-Type': 'multipart/form-data'
  91 + }
  92 + }).then(response => {
  93 + const res = response.data
  94 + if (res.code === 0) {
  95 + resolve(res.data)
  96 + } else {
  97 + reject(new Error(res.msg || 'Failed to upload file'))
  98 + }
  99 + }).catch(error => {
  100 + reject(error)
  101 + })
  102 + })
  103 +}
  104 +// 获取广告详情
  105 +export function getAdvertDetail(advertId) {
  106 + return new Promise((resolve, reject) => {
  107 + request({
  108 + url: '/advert.getAdvertDetail',
  109 + method: 'get',
  110 + params: { advertId }
  111 + }).then(response => {
  112 + const res = response.data
  113 + if (res.code === 0) {
  114 + resolve(res.data)
  115 + } else {
  116 + reject(new Error(res.msg || 'Failed to get advertisement detail'))
  117 + }
  118 + }).catch(error => {
  119 + reject(error)
  120 + })
  121 + })
  122 +}
  123 +
  124 +// 获取广告项列表
  125 +export function getAdvertItems(params) {
  126 + return new Promise((resolve, reject) => {
  127 + request({
  128 + url: '/advert.listAdvertItems',
  129 + method: 'get',
  130 + params
  131 + }).then(response => {
  132 + const res = response.data
  133 + resolve(res)
  134 + }).catch(error => {
  135 + reject(error)
  136 + })
  137 + })
  138 +}
  139 +
  140 +// 获取位置类型
  141 +export function getLocationTypes() {
  142 + return new Promise((resolve, reject) => {
  143 + request({
  144 + url: '/dict.listDict',
  145 + method: 'get',
  146 + params: { type: 'location_type_cd' }
  147 + }).then(response => {
  148 + const res = response.data
  149 + if (res.code === 0) {
  150 + resolve(res.data)
  151 + } else {
  152 + reject(new Error(res.msg || 'Failed to get location types'))
  153 + }
  154 + }).catch(error => {
  155 + reject(error)
  156 + })
  157 + })
  158 +}
0 159 \ No newline at end of file
... ...
src/components/admin/AddAdvert.vue 0 → 100644
  1 +<template>
  2 + <el-dialog :title="$t('advertManage.add.title')" :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('advertManage.add.adName')" prop="adName">
  5 + <el-input v-model="form.adName" :placeholder="$t('advertManage.add.adNamePlaceholder')" />
  6 + </el-form-item>
  7 +
  8 + <el-form-item :label="$t('advertManage.add.classify')" prop="classify">
  9 + <el-select v-model="form.classify" :placeholder="$t('advertManage.add.classifyPlaceholder')" style="width: 100%;">
  10 + <el-option v-for="item in classifyOptions" :key="item.value" :label="item.label" :value="item.value" />
  11 + </el-select>
  12 + </el-form-item>
  13 +
  14 + <el-form-item :label="$t('advertManage.add.locationTypeCd')" prop="locationTypeCd">
  15 + <el-select v-model="form.locationTypeCd" :placeholder="$t('advertManage.add.locationPlaceholder')" style="width: 100%;">
  16 + <el-option v-for="item in locationOptions" :key="item.value" :label="item.label" :value="item.value" />
  17 + </el-select>
  18 + </el-form-item>
  19 +
  20 + <el-form-item :label="$t('advertManage.add.advertType')" prop="advertType">
  21 + <el-select v-model="form.advertType" :placeholder="$t('advertManage.add.advertTypePlaceholder')" style="width: 100%;">
  22 + <el-option v-for="item in advertTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
  23 + </el-select>
  24 + </el-form-item>
  25 +
  26 + <el-form-item :label="$t('advertManage.add.pageUrl')">
  27 + <el-input v-model="form.pageUrl" :placeholder="$t('advertManage.add.pageUrlPlaceholder')" style="width: 100%;"/>
  28 + </el-form-item>
  29 +
  30 + <el-form-item :label="$t('advertManage.add.seq')" prop="seq">
  31 + <el-input v-model="form.seq" :placeholder="$t('advertManage.add.seqPlaceholder')" style="width: 100%;"/>
  32 + </el-form-item>
  33 +
  34 + <el-form-item :label="$t('advertManage.add.startTime')" prop="startTime">
  35 + <el-date-picker v-model="form.startTime" type="datetime"
  36 + :placeholder="$t('advertManage.add.startTimePlaceholder')" value-format="yyyy-MM-dd HH:mm:ss" style="width: 100%;"/>
  37 + </el-form-item>
  38 +
  39 + <el-form-item :label="$t('advertManage.add.endTime')" prop="endTime">
  40 + <el-date-picker v-model="form.endTime" type="datetime" :placeholder="$t('advertManage.add.endTimePlaceholder')" style="width: 100%;"
  41 + value-format="yyyy-MM-dd HH:mm:ss" />
  42 + </el-form-item>
  43 +
  44 + <el-form-item :label="$t('advertManage.add.viewType')" prop="viewType">
  45 + <el-select v-model="form.viewType" :placeholder="$t('advertManage.add.viewTypePlaceholder')" style="width: 100%;">
  46 + <el-option v-for="item in viewTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
  47 + </el-select>
  48 + </el-form-item>
  49 +
  50 + <el-form-item v-if="form.viewType === '8888'" :label="$t('advertManage.add.image')">
  51 + <upload-image-url ref="uploadImage" :limit="1" @notifyUploadCoverImage="handleImageChange" />
  52 + </el-form-item>
  53 +
  54 + <div class="dialog-footer">
  55 + <el-button @click="visible = false">{{ $t('common.cancel') }}</el-button>
  56 + <el-button type="primary" @click="handleSubmit">{{ $t('common.confirm') }}</el-button>
  57 + </div>
  58 + </el-form>
  59 + </el-dialog>
  60 +</template>
  61 +
  62 +<script>
  63 +import { saveAdvert } from '@/api/admin/advertManageApi'
  64 +import UploadImageUrl from '@/components/upload/UploadImageUrl'
  65 +
  66 +export default {
  67 + name: 'AddAdvert',
  68 + components: {
  69 + UploadImageUrl
  70 + },
  71 + data() {
  72 + return {
  73 + visible: false,
  74 + form: {
  75 + adName: '',
  76 + classify: '',
  77 + locationTypeCd: '',
  78 + advertType: '',
  79 + pageUrl: '',
  80 + seq: '',
  81 + startTime: '',
  82 + endTime: '',
  83 + viewType: '8888',
  84 + adTypeCd: '20000',
  85 + locationObjId: '-1',
  86 + vedioName:'',
  87 + photos: []
  88 + },
  89 + rules: {
  90 + adName: [
  91 + { required: true, message: this.$t('advertManage.validate.adNameRequired'), trigger: 'blur' }
  92 + ],
  93 + classify: [
  94 + { required: true, message: this.$t('advertManage.validate.classifyRequired'), trigger: 'change' }
  95 + ],
  96 + locationTypeCd: [
  97 + { required: true, message: this.$t('advertManage.validate.locationRequired'), trigger: 'change' }
  98 + ],
  99 + advertType: [
  100 + { required: true, message: this.$t('advertManage.validate.advertTypeRequired'), trigger: 'change' }
  101 + ],
  102 + seq: [
  103 + { required: true, message: this.$t('advertManage.validate.seqRequired'), trigger: 'blur' },
  104 + { pattern: /^\d+$/, message: this.$t('advertManage.validate.seqNumber'), trigger: 'blur' }
  105 + ],
  106 + startTime: [
  107 + { required: true, message: this.$t('advertManage.validate.startTimeRequired'), trigger: 'change' }
  108 + ],
  109 + endTime: [
  110 + { required: true, message: this.$t('advertManage.validate.endTimeRequired'), trigger: 'change' }
  111 + ],
  112 + viewType: [
  113 + { required: true, message: this.$t('advertManage.validate.viewTypeRequired'), trigger: 'change' }
  114 + ]
  115 + },
  116 + classifyOptions: [
  117 + { value: '9001', label: this.$t('advertManage.classify.logistics') },
  118 + { value: '9002', label: this.$t('advertManage.classify.catering') },
  119 + { value: '9003', label: this.$t('advertManage.classify.travel') },
  120 + { value: '9004', label: this.$t('advertManage.classify.hotel') },
  121 + { value: '9005', label: this.$t('advertManage.classify.education') },
  122 + { value: '9006', label: this.$t('advertManage.classify.internet') }
  123 + ],
  124 + locationOptions: [
  125 + { value: '1000', label: this.$t('advertManage.location.device') },
  126 + { value: '2000', label: this.$t('advertManage.location.ownerHome') },
  127 + { value: '3000', label: this.$t('advertManage.location.businessHome') },
  128 + { value: '5000', label: this.$t('advertManage.location.serviceHome') },
  129 + { value: '6000', label: this.$t('advertManage.location.convenienceHome') },
  130 + { value: '4000', label: this.$t('advertManage.location.staffHome') }
  131 + ],
  132 + advertTypeOptions: [
  133 + { value: '1', label: this.$t('advertManage.advertType.site') },
  134 + { value: '2', label: this.$t('advertManage.advertType.outside') },
  135 + { value: '3', label: this.$t('advertManage.advertType.noJump') }
  136 + ],
  137 + viewTypeOptions: [
  138 + { value: '8888', label: this.$t('advertManage.add.image') }
  139 + ]
  140 + }
  141 + },
  142 + methods: {
  143 + open() {
  144 + this.visible = true
  145 + this.resetForm()
  146 + },
  147 + resetForm() {
  148 + this.$refs.form && this.$refs.form.resetFields()
  149 + this.$refs.uploadImage && this.$refs.uploadImage.clear()
  150 + },
  151 + handleClose() {
  152 + this.resetForm()
  153 + },
  154 + handleImageChange(images) {
  155 + if (images && images.length > 0) {
  156 + this.form.photos = images
  157 + } else {
  158 + this.form.photos = []
  159 + }
  160 + },
  161 + async handleSubmit() {
  162 + try {
  163 + await this.$refs.form.validate()
  164 +
  165 + const params = {
  166 + ...this.form,
  167 + photos: this.form.photos
  168 + }
  169 +
  170 + await saveAdvert(params)
  171 + this.$message.success(this.$t('advertManage.add.success'))
  172 + this.$emit('success')
  173 + this.visible = false
  174 + } catch (error) {
  175 + console.error(error)
  176 + }
  177 + }
  178 + }
  179 +}
  180 +</script>
0 181 \ No newline at end of file
... ...
src/components/admin/DeleteAdvert.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('advertManage.delete.title')"
  4 + :visible.sync="visible"
  5 + width="30%"
  6 + @close="handleClose">
  7 + <p>{{ $t('advertManage.delete.confirm') }}</p>
  8 + <span slot="footer" class="dialog-footer">
  9 + <el-button @click="visible = false">{{ $t('common.cancel') }}</el-button>
  10 + <el-button type="primary" @click="handleConfirm">{{ $t('common.confirm') }}</el-button>
  11 + </span>
  12 + </el-dialog>
  13 +</template>
  14 +
  15 +<script>
  16 +import { deleteAdvert } from '@/api/admin/advertManageApi'
  17 +
  18 +export default {
  19 + name: 'DeleteAdvert',
  20 + data() {
  21 + return {
  22 + visible: false,
  23 + advertId: ''
  24 + }
  25 + },
  26 + methods: {
  27 + open(row) {
  28 + this.visible = true
  29 + this.advertId = row.advertId
  30 + },
  31 + handleClose() {
  32 + this.advertId = ''
  33 + },
  34 + async handleConfirm() {
  35 + try {
  36 + await deleteAdvert(this.advertId)
  37 + this.$message.success(this.$t('advertManage.delete.success'))
  38 + this.$emit('success')
  39 + this.visible = false
  40 + } catch (error) {
  41 + console.error(error)
  42 + }
  43 + }
  44 + }
  45 +}
  46 +</script>
0 47 \ No newline at end of file
... ...
src/components/admin/EditAdvert.vue 0 → 100644
  1 +<template>
  2 + <el-dialog :title="$t('advertManage.edit.title')" :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('advertManage.edit.adName')" prop="adName">
  5 + <el-input v-model="form.adName" :placeholder="$t('advertManage.edit.adNamePlaceholder')" />
  6 + </el-form-item>
  7 +
  8 + <el-form-item :label="$t('advertManage.edit.classify')" prop="classify">
  9 + <el-select v-model="form.classify" :placeholder="$t('advertManage.edit.classifyPlaceholder')" style="width:100%">
  10 + <el-option v-for="item in classifyOptions" :key="item.value" :label="item.label" :value="item.value" />
  11 + </el-select>
  12 + </el-form-item>
  13 +
  14 + <el-form-item :label="$t('advertManage.edit.locationTypeCd')" prop="locationTypeCd">
  15 + <el-select v-model="form.locationTypeCd" :placeholder="$t('advertManage.edit.locationPlaceholder')" style="width:100%">
  16 + <el-option v-for="item in locationOptions" :key="item.value" :label="item.label" :value="item.value" />
  17 + </el-select>
  18 + </el-form-item>
  19 +
  20 + <el-form-item :label="$t('advertManage.edit.advertType')" prop="advertType">
  21 + <el-select v-model="form.advertType" :placeholder="$t('advertManage.edit.advertTypePlaceholder')" style="width:100%">
  22 + <el-option v-for="item in advertTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
  23 + </el-select>
  24 + </el-form-item>
  25 +
  26 + <el-form-item :label="$t('advertManage.edit.pageUrl')">
  27 + <el-input v-model="form.pageUrl" :placeholder="$t('advertManage.edit.pageUrlPlaceholder')" />
  28 + </el-form-item>
  29 +
  30 + <el-form-item :label="$t('advertManage.edit.seq')" prop="seq">
  31 + <el-input v-model="form.seq" :placeholder="$t('advertManage.edit.seqPlaceholder')" />
  32 + </el-form-item>
  33 +
  34 + <el-form-item :label="$t('advertManage.edit.startTime')" prop="startTime">
  35 + <el-date-picker v-model="form.startTime" type="datetime"
  36 + :placeholder="$t('advertManage.edit.startTimePlaceholder')" value-format="yyyy-MM-dd HH:mm:ss" style="width:100%"/>
  37 + </el-form-item>
  38 +
  39 + <el-form-item :label="$t('advertManage.edit.endTime')" prop="endTime">
  40 + <el-date-picker v-model="form.endTime" type="datetime" :placeholder="$t('advertManage.edit.endTimePlaceholder')" style="width:100%"
  41 + value-format="yyyy-MM-dd HH:mm:ss" />
  42 + </el-form-item>
  43 +
  44 + <el-form-item :label="$t('advertManage.edit.viewType')" prop="viewType">
  45 + <el-select v-model="form.viewType" :placeholder="$t('advertManage.edit.viewTypePlaceholder')" style="width:100%">
  46 + <el-option v-for="item in viewTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
  47 + </el-select>
  48 + </el-form-item>
  49 +
  50 + <el-form-item v-if="form.viewType === '8888'" :label="$t('advertManage.edit.image')">
  51 + <upload-image-url ref="uploadImage" :limit="1" @notifyUploadCoverImage="handleImageChange" />
  52 + </el-form-item>
  53 +
  54 + <div class="dialog-footer">
  55 + <el-button @click="visible = false">{{ $t('common.cancel') }}</el-button>
  56 + <el-button type="primary" @click="handleSubmit">{{ $t('common.confirm') }}</el-button>
  57 + </div>
  58 + </el-form>
  59 + </el-dialog>
  60 +</template>
  61 +
  62 +<script>
  63 +import { updateAdvert, getAdvertItems } from '@/api/admin/advertManageApi'
  64 +import UploadImageUrl from '@/components/upload/UploadImageUrl'
  65 +
  66 +export default {
  67 + name: 'EditAdvert',
  68 + components: {
  69 + UploadImageUrl
  70 + },
  71 + data() {
  72 + return {
  73 + visible: false,
  74 + form: {
  75 + advertId: '',
  76 + adName: '',
  77 + classify: '',
  78 + locationTypeCd: '',
  79 + advertType: '',
  80 + pageUrl: '',
  81 + seq: '',
  82 + startTime: '',
  83 + endTime: '',
  84 + viewType: '8888'
  85 + },
  86 + defaultImages: [],
  87 + rules: {
  88 + adName: [
  89 + { required: true, message: this.$t('advertManage.validate.adNameRequired'), trigger: 'blur' }
  90 + ],
  91 + classify: [
  92 + { required: true, message: this.$t('advertManage.validate.classifyRequired'), trigger: 'change' }
  93 + ],
  94 + locationTypeCd: [
  95 + { required: true, message: this.$t('advertManage.validate.locationRequired'), trigger: 'change' }
  96 + ],
  97 + advertType: [
  98 + { required: true, message: this.$t('advertManage.validate.advertTypeRequired'), trigger: 'change' }
  99 + ],
  100 + seq: [
  101 + { required: true, message: this.$t('advertManage.validate.seqRequired'), trigger: 'blur' },
  102 + { pattern: /^\d+$/, message: this.$t('advertManage.validate.seqNumber'), trigger: 'blur' }
  103 + ],
  104 + startTime: [
  105 + { required: true, message: this.$t('advertManage.validate.startTimeRequired'), trigger: 'change' }
  106 + ],
  107 + endTime: [
  108 + { required: true, message: this.$t('advertManage.validate.endTimeRequired'), trigger: 'change' }
  109 + ],
  110 + viewType: [
  111 + { required: true, message: this.$t('advertManage.validate.viewTypeRequired'), trigger: 'change' }
  112 + ]
  113 + },
  114 + classifyOptions: [
  115 + { value: '9001', label: this.$t('advertManage.classify.logistics') },
  116 + { value: '9002', label: this.$t('advertManage.classify.catering') },
  117 + { value: '9003', label: this.$t('advertManage.classify.travel') },
  118 + { value: '9004', label: this.$t('advertManage.classify.hotel') },
  119 + { value: '9005', label: this.$t('advertManage.classify.education') },
  120 + { value: '9006', label: this.$t('advertManage.classify.internet') }
  121 + ],
  122 + locationOptions: [
  123 + { value: '1000', label: this.$t('advertManage.location.device') },
  124 + { value: '2000', label: this.$t('advertManage.location.ownerHome') },
  125 + { value: '3000', label: this.$t('advertManage.location.businessHome') },
  126 + { value: '5000', label: this.$t('advertManage.location.serviceHome') },
  127 + { value: '6000', label: this.$t('advertManage.location.convenienceHome') },
  128 + { value: '4000', label: this.$t('advertManage.location.staffHome') }
  129 + ],
  130 + advertTypeOptions: [
  131 + { value: '1', label: this.$t('advertManage.advertType.site') },
  132 + { value: '2', label: this.$t('advertManage.advertType.outside') },
  133 + { value: '3', label: this.$t('advertManage.advertType.noJump') }
  134 + ],
  135 + viewTypeOptions: [
  136 + { value: '8888', label: this.$t('advertManage.edit.image') }
  137 + ]
  138 + }
  139 + },
  140 + methods: {
  141 + open(row) {
  142 + this.visible = true
  143 + this.resetForm()
  144 + this.form = { ...row }
  145 + this.loadAdvertItems(row.advertId)
  146 + },
  147 + handleImageChange(images) {
  148 + if (images && images.length > 0) {
  149 + this.form.photos = images
  150 + } else {
  151 + this.form.photos = []
  152 + }
  153 + },
  154 + async loadAdvertItems(advertId) {
  155 + try {
  156 + const { advertItems } = await getAdvertItems({ advertId,page:1,row:100 })
  157 + this.defaultImages = advertItems.filter(item => item.itemTypeCd === '8888').map(item => (item.url))
  158 + this.form.photos = this.defaultImages
  159 + setTimeout(() => {
  160 + this.$refs.uploadImage.setImages(this.defaultImages)
  161 + }, 500)
  162 + } catch (error) {
  163 + console.error(error)
  164 + }
  165 + },
  166 + resetForm() {
  167 + this.$refs.form && this.$refs.form.resetFields()
  168 + this.$refs.uploadImage && this.$refs.uploadImage.clear()
  169 + this.defaultImages = []
  170 + },
  171 + handleClose() {
  172 + this.resetForm()
  173 + },
  174 + async handleSubmit() {
  175 + try {
  176 + await this.$refs.form.validate()
  177 +
  178 +
  179 + const params = {
  180 + ...this.form,
  181 + photos: this.form.photos
  182 + }
  183 +
  184 + await updateAdvert(params)
  185 + this.$message.success(this.$t('advertManage.edit.success'))
  186 + this.$emit('success')
  187 + this.visible = false
  188 + } catch (error) {
  189 + console.error(error)
  190 + }
  191 + }
  192 + }
  193 +}
  194 +</script>
0 195 \ No newline at end of file
... ...
src/components/admin/WriteAdvertMachine.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('advertManage.machine.title')"
  4 + :visible.sync="visible"
  5 + width="50%"
  6 + @close="handleClose">
  7 + <el-form label-width="120px">
  8 + <el-form-item :label="$t('advertManage.machine.machineCode')">
  9 + <el-input
  10 + v-model="machineCode"
  11 + :placeholder="$t('advertManage.machine.machineCodePlaceholder')" />
  12 + </el-form-item>
  13 + </el-form>
  14 + <span slot="footer" class="dialog-footer">
  15 + <el-button @click="visible = false">{{ $t('common.cancel') }}</el-button>
  16 + <el-button type="primary" @click="handleView">{{ $t('advertManage.machine.view') }}</el-button>
  17 + </span>
  18 + </el-dialog>
  19 +</template>
  20 +
  21 +<script>
  22 +export default {
  23 + name: 'WriteAdvertMachine',
  24 + data() {
  25 + return {
  26 + visible: false,
  27 + machineCode: ''
  28 + }
  29 + },
  30 + methods: {
  31 + open() {
  32 + this.visible = true
  33 + this.machineCode = ''
  34 + },
  35 + handleClose() {
  36 + this.machineCode = ''
  37 + },
  38 + handleView() {
  39 + if (!this.machineCode) {
  40 + this.$message.error(this.$t('advertManage.validate.machineCodeRequired'))
  41 + return
  42 + }
  43 + this.$router.push({
  44 + path: '/advertVedio',
  45 + query: {
  46 + machineCode: this.machineCode,
  47 + communityId: this.$store.getters.communityId
  48 + }
  49 + })
  50 + this.visible = false
  51 + }
  52 + }
  53 +}
  54 +</script>
0 55 \ No newline at end of file
... ...
src/i18n/index.js
... ... @@ -102,6 +102,7 @@ import { messages as marketGoodsItemManageMessages } from &#39;../views/market/marke
102 102 import { messages as marketRuleMessages } from '../views/market/marketRuleLang'
103 103 import { messages as marketBlacklistManageMessages } from '../views/market/marketBlacklistManageLang'
104 104 import { messages as marketLogMessages } from '../views/market/marketLogLang'
  105 +import { messages as advertManageMessages } from '../views/admin/advertManageLang'
105 106  
106 107 Vue.use(VueI18n)
107 108  
... ... @@ -208,6 +209,7 @@ const messages = {
208 209 ...marketRuleMessages.en,
209 210 ...marketBlacklistManageMessages.en,
210 211 ...marketLogMessages.en,
  212 + ...advertManageMessages.en,
211 213 },
212 214 zh: {
213 215 ...loginMessages.zh,
... ... @@ -310,6 +312,7 @@ const messages = {
310 312 ...marketRuleMessages.zh,
311 313 ...marketBlacklistManageMessages.zh,
312 314 ...marketLogMessages.zh,
  315 + ...advertManageMessages.zh,
313 316 }
314 317 }
315 318  
... ...
src/router/index.js
... ... @@ -487,15 +487,20 @@ const routes = [
487 487 component: () => import('@/views/market/marketRuleList.vue')
488 488 },
489 489 {
490   - path:'/pages/admin/marketBlacklistManage',
491   - name:'/pages/admin/marketBlacklistManage',
  490 + path: '/pages/admin/marketBlacklistManage',
  491 + name: '/pages/admin/marketBlacklistManage',
492 492 component: () => import('@/views/market/marketBlacklistManageList.vue')
493   - },
494   - {
495   - path:'/pages/admin/marketLog',
496   - name:'/pages/admin/marketLog',
497   - component: () => import('@/views/market/marketLogList.vue')
498   - },
  493 + },
  494 + {
  495 + path: '/pages/admin/marketLog',
  496 + name: '/pages/admin/marketLog',
  497 + component: () => import('@/views/market/marketLogList.vue')
  498 + },
  499 + {
  500 + path: '/pages/property/advertManage',
  501 + name: '/pages/property/advertManage',
  502 + component: () => import('@/views/admin/advertManageList.vue')
  503 + },
499 504 // 其他子路由可以在这里添加
500 505 ]
501 506 },
... ...
src/views/admin/advertManageLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + advertManage: {
  4 + search: {
  5 + title: 'Search Conditions',
  6 + hide: 'Hide',
  7 + more: 'More',
  8 + adNamePlaceholder: 'Please enter the advertisement name',
  9 + classifyPlaceholder: 'Please select the advertisement category',
  10 + locationPlaceholder: 'Please select the placement location'
  11 + },
  12 + list: {
  13 + title: 'Advertisement Information',
  14 + publish: 'Publish',
  15 + viewAdvert: 'View Advertisement'
  16 + },
  17 + table: {
  18 + advertId: 'Advertisement ID',
  19 + adName: 'Advertisement Name',
  20 + classify: 'Advertisement Category',
  21 + location: 'Placement Location',
  22 + advertType: 'Publish Type',
  23 + startTime: 'Start Time',
  24 + endTime: 'End Time',
  25 + createTime: 'Creation Time'
  26 + },
  27 + advertType: {
  28 + site: 'Site',
  29 + outside: 'Outside',
  30 + noJump: 'No Jump'
  31 + },
  32 + classify: {
  33 + logistics: 'Logistics',
  34 + catering: 'Catering',
  35 + travel: 'Travel',
  36 + hotel: 'Hotel',
  37 + education: 'Education',
  38 + internet: 'Internet'
  39 + },
  40 + add: {
  41 + title: 'Publish Advertisement',
  42 + adName: 'Advertisement Name',
  43 + adNamePlaceholder: 'Required, please enter the advertisement name',
  44 + classify: 'Advertisement Category',
  45 + classifyPlaceholder: 'Required, please select the advertisement category',
  46 + locationTypeCd: 'Placement Location',
  47 + locationPlaceholder: 'Required, please select the placement location',
  48 + advertType: 'Publish Type',
  49 + advertTypePlaceholder: 'Required, please select the publish type',
  50 + pageUrl: 'Jump Path',
  51 + pageUrlPlaceholder: 'Please enter the jump path',
  52 + seq: 'Play Order',
  53 + seqPlaceholder: 'Required, please enter the play order',
  54 + startTime: 'Start Time',
  55 + startTimePlaceholder: 'Required, please select the start time',
  56 + endTime: 'End Time',
  57 + endTimePlaceholder: 'Required, please select the end time',
  58 + viewType: 'Play Method',
  59 + viewTypePlaceholder: 'Required, please select the play method',
  60 + image: 'Image (800 * 373)',
  61 + success: 'Advertisement published successfully'
  62 + },
  63 + edit: {
  64 + title: 'Edit Advertisement',
  65 + adName: 'Advertisement Name',
  66 + adNamePlaceholder: 'Required, please enter the advertisement name',
  67 + classify: 'Advertisement Category',
  68 + classifyPlaceholder: 'Required, please select the advertisement category',
  69 + locationTypeCd: 'Placement Location',
  70 + locationPlaceholder: 'Required, please select the placement location',
  71 + advertType: 'Publish Type',
  72 + advertTypePlaceholder: 'Required, please select the publish type',
  73 + pageUrl: 'Jump Path',
  74 + pageUrlPlaceholder: 'Please enter the jump path',
  75 + seq: 'Play Order',
  76 + seqPlaceholder: 'Required, please enter the play order',
  77 + startTime: 'Start Time',
  78 + startTimePlaceholder: 'Required, please select the start time',
  79 + endTime: 'End Time',
  80 + endTimePlaceholder: 'Required, please select the end time',
  81 + viewType: 'Play Method',
  82 + viewTypePlaceholder: 'Required, please select the play method',
  83 + image: 'Image (800 * 373)',
  84 + success: 'Advertisement updated successfully'
  85 + },
  86 + delete: {
  87 + title: 'Confirm Operation',
  88 + confirm: 'Are you sure to delete this advertisement?',
  89 + success: 'Advertisement deleted successfully'
  90 + },
  91 + machine: {
  92 + title: 'Advertisement Device Code',
  93 + machineCode: 'Device Code',
  94 + machineCodePlaceholder: 'Required, please enter the device code',
  95 + view: 'View Advertisement'
  96 + },
  97 + validate: {
  98 + adNameRequired: 'Advertisement name is required',
  99 + classifyRequired: 'Advertisement category is required',
  100 + locationRequired: 'Placement location is required',
  101 + advertTypeRequired: 'Publish type is required',
  102 + seqRequired: 'Play order is required',
  103 + seqNumber: 'Play order must be a number',
  104 + startTimeRequired: 'Start time is required',
  105 + endTimeRequired: 'End time is required',
  106 + viewTypeRequired: 'Play method is required',
  107 + imageRequired: 'Please upload image',
  108 + machineCodeRequired: 'Device code is required'
  109 + },
  110 + fetchError: 'Failed to get advertisement list',
  111 + fetchLocationError: 'Failed to get location types'
  112 + }
  113 + },
  114 + zh: {
  115 + advertManage: {
  116 + search: {
  117 + title: '查询条件',
  118 + hide: '隐藏',
  119 + more: '更多',
  120 + adNamePlaceholder: '请输入广告名称',
  121 + classifyPlaceholder: '请选择广告分类',
  122 + locationPlaceholder: '请选择投放位置'
  123 + },
  124 + list: {
  125 + title: '广告信息',
  126 + publish: '发布',
  127 + viewAdvert: '查看广告'
  128 + },
  129 + table: {
  130 + advertId: '广告ID',
  131 + adName: '广告名称',
  132 + classify: '广告分类',
  133 + location: '投放位置',
  134 + advertType: '发布类型',
  135 + startTime: '投放时间',
  136 + endTime: '结束时间',
  137 + createTime: '创建时间'
  138 + },
  139 + advertType: {
  140 + site: '站内',
  141 + outside: '站外',
  142 + noJump: '不跳转'
  143 + },
  144 + classify: {
  145 + logistics: '物流',
  146 + catering: '餐饮',
  147 + travel: '旅游',
  148 + hotel: '酒店',
  149 + education: '教育',
  150 + internet: '互联网'
  151 + },
  152 + add: {
  153 + title: '发布广告',
  154 + adName: '广告名称',
  155 + adNamePlaceholder: '必填,请填写广告名称',
  156 + classify: '广告分类',
  157 + classifyPlaceholder: '必填,请选择广告分类',
  158 + locationTypeCd: '投放位置',
  159 + locationPlaceholder: '必填,请选择投放位置',
  160 + advertType: '发布类型',
  161 + advertTypePlaceholder: '必填,请选择发布类型',
  162 + pageUrl: '跳转路径',
  163 + pageUrlPlaceholder: '请填写跳转路径',
  164 + seq: '播放顺序',
  165 + seqPlaceholder: '必填,请填写播放顺序',
  166 + startTime: '投放时间',
  167 + startTimePlaceholder: '必填,请填写投放时间',
  168 + endTime: '结束时间',
  169 + endTimePlaceholder: '必填,请填写结束时间',
  170 + viewType: '播放方式',
  171 + viewTypePlaceholder: '必填,请选择播放方式',
  172 + image: '图片(800 * 373)',
  173 + success: '广告发布成功'
  174 + },
  175 + edit: {
  176 + title: '修改广告',
  177 + adName: '广告名称',
  178 + adNamePlaceholder: '必填,请填写广告名称',
  179 + classify: '广告分类',
  180 + classifyPlaceholder: '必填,请选择广告分类',
  181 + locationTypeCd: '投放位置',
  182 + locationPlaceholder: '必填,请选择投放位置',
  183 + advertType: '发布类型',
  184 + advertTypePlaceholder: '必填,请选择发布类型',
  185 + pageUrl: '跳转路径',
  186 + pageUrlPlaceholder: '请填写跳转路径',
  187 + seq: '播放顺序',
  188 + seqPlaceholder: '必填,请填写播放顺序',
  189 + startTime: '投放时间',
  190 + startTimePlaceholder: '必填,请填写投放时间',
  191 + endTime: '结束时间',
  192 + endTimePlaceholder: '必填,请填写结束时间',
  193 + viewType: '播放方式',
  194 + viewTypePlaceholder: '必填,请选择播放方式',
  195 + image: '图片(800 * 373)',
  196 + success: '广告修改成功'
  197 + },
  198 + delete: {
  199 + title: '请确认您的操作',
  200 + confirm: '确定删除发布广告?',
  201 + success: '广告删除成功'
  202 + },
  203 + machine: {
  204 + title: '广告设备码',
  205 + machineCode: '设备编码',
  206 + machineCodePlaceholder: '必填,请填写设备编码',
  207 + view: '查看广告'
  208 + },
  209 + validate: {
  210 + adNameRequired: 'Advertisement name is required',
  211 + classifyRequired: 'Advertisement category is required',
  212 + locationRequired: 'Placement location is required',
  213 + advertTypeRequired: 'Publish type is required',
  214 + seqRequired: 'Play order is required',
  215 + seqNumber: 'Play order must be a number',
  216 + startTimeRequired: 'Start time is required',
  217 + endTimeRequired: 'End time is required',
  218 + viewTypeRequired: 'Play method is required',
  219 + imageRequired: 'Please upload image',
  220 + machineCodeRequired: 'Device code is required'
  221 + },
  222 + fetchError: '获取广告列表失败',
  223 + fetchLocationError: '获取位置类型失败'
  224 + }
  225 + }
  226 +}
0 227 \ No newline at end of file
... ...
src/views/admin/advertManageList.vue 0 → 100644
  1 +<template>
  2 + <div class="advert-manage-container">
  3 + <el-card class="search-wrapper">
  4 + <div slot="header" class="clearfix flex justify-between">
  5 + <span>{{ $t('advertManage.search.title') }}</span>
  6 + <el-button style="float: right; padding: 3px 0" type="text" @click="toggleMoreCondition">
  7 + {{ advertManageInfo.moreCondition ? $t('advertManage.search.hide') : $t('advertManage.search.more') }}
  8 + </el-button>
  9 + </div>
  10 + <el-row :gutter="20">
  11 + <el-col :span="4">
  12 + <el-input v-model="advertManageInfo.conditions.adName"
  13 + :placeholder="$t('advertManage.search.adNamePlaceholder')" clearable />
  14 + </el-col>
  15 + <el-col :span="4">
  16 + <el-select v-model="advertManageInfo.conditions.classify"
  17 + :placeholder="$t('advertManage.search.classifyPlaceholder')" clearable>
  18 + <el-option v-for="item in classifyOptions" :key="item.value" :label="item.label" :value="item.value" />
  19 + </el-select>
  20 + </el-col>
  21 + <el-col :span="4">
  22 + <el-button type="primary" @click="queryAdvert">{{ $t('common.search') }}</el-button>
  23 + <el-button @click="resetAdvert">{{ $t('common.reset') }}</el-button>
  24 + </el-col>
  25 + </el-row>
  26 + <el-row v-show="advertManageInfo.moreCondition" :gutter="20" style="margin-top: 15px;">
  27 + <el-col :span="4">
  28 + <el-select v-model="advertManageInfo.conditions.locationTypeCd"
  29 + :placeholder="$t('advertManage.search.locationPlaceholder')" clearable>
  30 + <el-option v-for="item in advertManageInfo.locationTypeCds" :key="item.statusCd" :label="item.name"
  31 + :value="item.statusCd" />
  32 + </el-select>
  33 + </el-col>
  34 + </el-row>
  35 + </el-card>
  36 +
  37 + <el-card class="list-wrapper">
  38 + <div slot="header" class="clearfix flex justify-between">
  39 + <span>{{ $t('advertManage.list.title') }}</span>
  40 + <div style="float: right;">
  41 + <el-button type="primary" size="small" @click="openAddAdvert">{{ $t('advertManage.list.publish') }}</el-button>
  42 + <!-- <el-button type="primary" size="small" @click="viewAdvertPhoto">{{ $t('advertManage.list.viewAdvert')
  43 + }}</el-button> -->
  44 + </div>
  45 + </div>
  46 +
  47 + <el-table v-loading="loading" :data="advertManageInfo.adverts" border style="width: 100%">
  48 + <el-table-column prop="advertId" :label="$t('advertManage.table.advertId')" align="center" />
  49 + <el-table-column prop="adName" :label="$t('advertManage.table.adName')" align="center" />
  50 + <el-table-column prop="classifyName" :label="$t('advertManage.table.classify')" align="center" />
  51 + <el-table-column prop="locationObjName" :label="$t('advertManage.table.location')" align="center" />
  52 + <el-table-column :label="$t('advertManage.table.advertType')" align="center">
  53 + <template slot-scope="scope">
  54 + {{ advertManageInfo.advertTypeName[scope.row.advertType] }}
  55 + </template>
  56 + </el-table-column>
  57 + <el-table-column prop="startTime" :label="$t('advertManage.table.startTime')" align="center" />
  58 + <el-table-column prop="endTime" :label="$t('advertManage.table.endTime')" align="center" />
  59 + <el-table-column prop="createTime" :label="$t('advertManage.table.createTime')" align="center" />
  60 + <el-table-column :label="$t('common.operation')" align="center" width="200">
  61 + <template slot-scope="scope">
  62 + <el-button size="mini" @click="openEditAdvert(scope.row)">{{ $t('common.edit') }}</el-button>
  63 + <el-button size="mini" type="danger" @click="openDeleteAdvert(scope.row)">{{ $t('common.delete')
  64 + }}</el-button>
  65 + </template>
  66 + </el-table-column>
  67 + </el-table>
  68 +
  69 + <el-pagination :current-page.sync="page.current" :page-sizes="[10, 20, 30, 50]" :page-size="page.size"
  70 + :total="page.total" layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange"
  71 + @current-change="handleCurrentChange" />
  72 + </el-card>
  73 +
  74 + <add-advert ref="addAdvert" @success="handleSuccess" />
  75 + <edit-advert ref="editAdvert" @success="handleSuccess" />
  76 + <delete-advert ref="deleteAdvert" @success="handleSuccess" />
  77 + <write-advert-machine ref="writeAdvertMachine" />
  78 + </div>
  79 +</template>
  80 +
  81 +<script>
  82 +import { listAdverts } from '@/api/admin/advertManageApi'
  83 +import AddAdvert from '@/components/admin/AddAdvert'
  84 +import EditAdvert from '@/components/admin/EditAdvert'
  85 +import DeleteAdvert from '@/components/admin/DeleteAdvert'
  86 +import WriteAdvertMachine from '@/components/admin/WriteAdvertMachine'
  87 +
  88 +export default {
  89 + name: 'AdvertManageList',
  90 + components: {
  91 + AddAdvert,
  92 + EditAdvert,
  93 + DeleteAdvert,
  94 + WriteAdvertMachine
  95 + },
  96 + data() {
  97 + return {
  98 + loading: false,
  99 + advertManageInfo: {
  100 + advertTypeName: ['', this.$t('advertManage.advertType.site'), this.$t('advertManage.advertType.outside'), this.$t('advertManage.advertType.noJump')],
  101 + adverts: [],
  102 + moreCondition: false,
  103 + locationTypeCds: [],
  104 + conditions: {
  105 + adName: '',
  106 + classify: '',
  107 + locationTypeCd: ''
  108 + }
  109 + },
  110 + classifyOptions: [
  111 + { value: '9001', label: this.$t('advertManage.classify.logistics') },
  112 + { value: '9002', label: this.$t('advertManage.classify.catering') },
  113 + { value: '9003', label: this.$t('advertManage.classify.travel') },
  114 + { value: '9004', label: this.$t('advertManage.classify.hotel') },
  115 + { value: '9005', label: this.$t('advertManage.classify.education') },
  116 + { value: '9006', label: this.$t('advertManage.classify.internet') }
  117 + ],
  118 + page: {
  119 + current: 1,
  120 + size: 10,
  121 + total: 0
  122 + }
  123 + }
  124 + },
  125 + created() {
  126 + this.getList()
  127 + this.getLocationTypes()
  128 + },
  129 + methods: {
  130 + async getList() {
  131 + try {
  132 + this.loading = true
  133 + const params = {
  134 + page: this.page.current,
  135 + row: this.page.size,
  136 + ...this.advertManageInfo.conditions
  137 + }
  138 + const { data, total } = await listAdverts(params)
  139 + this.advertManageInfo.adverts = data
  140 + this.page.total = total
  141 + } catch (error) {
  142 + this.$message.error(this.$t('advertManage.fetchError'))
  143 + } finally {
  144 + this.loading = false
  145 + }
  146 + },
  147 + async getLocationTypes() {
  148 + try {
  149 + // 这里应该调用获取位置类型的API
  150 + // const data = await getLocationTypes()
  151 + // this.advertManageInfo.locationTypeCds = data
  152 + } catch (error) {
  153 + this.$message.error(this.$t('advertManage.fetchLocationError'))
  154 + }
  155 + },
  156 + queryAdvert() {
  157 + this.page.current = 1
  158 + this.getList()
  159 + },
  160 + resetAdvert() {
  161 + this.advertManageInfo.conditions = {
  162 + adName: '',
  163 + classify: '',
  164 + locationTypeCd: ''
  165 + }
  166 + this.getList()
  167 + },
  168 + toggleMoreCondition() {
  169 + this.advertManageInfo.moreCondition = !this.advertManageInfo.moreCondition
  170 + },
  171 + openAddAdvert() {
  172 + this.$refs.addAdvert.open()
  173 + },
  174 + openEditAdvert(row) {
  175 + this.$refs.editAdvert.open(row)
  176 + },
  177 + openDeleteAdvert(row) {
  178 + this.$refs.deleteAdvert.open(row)
  179 + },
  180 + viewAdvertPhoto() {
  181 + this.$refs.writeAdvertMachine.open()
  182 + },
  183 + handleSuccess() {
  184 + this.getList()
  185 + },
  186 + handleSizeChange(val) {
  187 + this.page.size = val
  188 + this.getList()
  189 + },
  190 + handleCurrentChange(val) {
  191 + this.page.current = val
  192 + this.getList()
  193 + }
  194 + }
  195 +}
  196 +</script>
  197 +
  198 +<style lang="scss" scoped>
  199 +.advert-manage-container {
  200 + padding: 20px;
  201 +
  202 + .search-wrapper {
  203 + margin-bottom: 20px;
  204 + }
  205 +
  206 + .list-wrapper {
  207 + .el-pagination {
  208 + margin-top: 20px;
  209 + text-align: right;
  210 + }
  211 + }
  212 +}
  213 +</style>
0 214 \ No newline at end of file
... ...