diff --git a/.env.production b/.env.production index 61a7f6d..07c72ef 100644 --- a/.env.production +++ b/.env.production @@ -1,2 +1,2 @@ -#VUE_APP_BASE_API = 'http://192.168.100.22:2900' -VUE_APP_BASE_API = 'https://puzzle-admin.kingsome.cn' +VUE_APP_BASE_API = 'http://192.168.100.22:2900' +#VUE_APP_BASE_API = 'https://puzzle-admin.kingsome.cn' diff --git a/src/api/mail.ts b/src/api/mail.ts new file mode 100644 index 0000000..a5163bf --- /dev/null +++ b/src/api/mail.ts @@ -0,0 +1,63 @@ + +import request from '@/utils/request' + +export interface IMailItem { + _id?: string + index?: number + itemId?: string + name?: string + count: number +} + +export interface IMailData { + _id?: string + senderShop?: string + sender?: string + title?: string + content?: string + type: number + accounts: string[] + shops: string[] + items: IMailItem[] + sendTime?: number + endTime?: number +} + +export const defaultMailItem: IMailItem = { + count: 1 +} + +export const defaultMailData: IMailData = { + items: [], + shops: [], + type: 0, + accounts: [] +} + +export const getMails = (params: any) => + request({ + url: '/api/mails', + method: 'post', + params + }) + +export const getMail = (id: string, params: any) => + request({ + url: `/api/mail/${id}`, + method: 'get', + params + }) + +export const saveMail = (data: any) => + request({ + url: '/api/mail/save', + method: 'post', + data + }) + +export const deleteMail = (data: any) => + request({ + url: '/api/mail/delete', + method: 'post', + data + }) diff --git a/src/api/shop.ts b/src/api/shop.ts index 8948eb2..7f05019 100644 --- a/src/api/shop.ts +++ b/src/api/shop.ts @@ -139,3 +139,14 @@ export const updateShopShareCfg = (data: any) => method: 'post', data }) + +/** + * 获取店铺转盘配置 + * @param data + */ +export const getShopUsers = (data: any) => + request({ + url: '/api/shop/game_users', + method: 'post', + data + }) diff --git a/src/utils/Extend.ts b/src/utils/Extend.ts index aa2b9c4..d2bd9e7 100644 --- a/src/utils/Extend.ts +++ b/src/utils/Extend.ts @@ -1,4 +1,20 @@ - +interface Date { + /** + * 增加n天 + * @param {number} days + * @return {Date} + */ + addDays(days: number): Date +} +// eslint-disable-next-line no-extend-native +Object.defineProperties(Date.prototype, { + addDays: { + value: function(days: number) { + return new Date(this.getTime() + days * 3600 * 24 * 1000) + }, + writable: true + } +}) interface Array { /** * 如果数组中没有要放入的对象,则将对象放入数组 diff --git a/src/views/mail/edit.vue b/src/views/mail/edit.vue index 7aa5383..5a61a34 100644 --- a/src/views/mail/edit.vue +++ b/src/views/mail/edit.vue @@ -1,6 +1,5 @@ @@ -389,30 +203,19 @@ import { Component, Vue, Watch } from 'vue-property-decorator' import { AppModule } from '@/store/modules/app' import { ITagView, TagsViewModule } from '@/store/modules/tags-view' -import MaterialInput from '@/components/MaterialInput/index.vue' -import Sticky from '@/components/Sticky/index.vue' import UploadImage from '@/components/UploadImage/index.vue' -import RegionPicker from '@/components/RegionPicker/index.vue' -import { getMyShop, getShops } from '@/api/shop' -import { defaultActivityData, defaultRewardData, getActivity, IRewardData, saveActivity } from '@/api/activity' -import { sec2TimeStr, timeStr2Sec } from '@/utils' -import { getAllCategory } from '@/api/question' -import { cloneDeep } from 'lodash' -import { getCoupons, ICouponData } from '@/api/coupon' -import { IShopData } from '@/api/types' -import { ElTree } from 'element-ui/types/tree' +import { getShops, getShopUsers } from '@/api/shop' import { UserModule } from '@/store/modules/user' -import UploadCorpImage from '@/components/UploadCorpImage/index.vue' -import { EVENT_ACTIVITY_UPDATE, EVENT_COUPON_UPDATE, EVENT_SHOP_UPDATE, EventBus } from '@/utils/event-bus' +import { EVENT_COUPON_UPDATE, EVENT_SHOP_UPDATE, EventBus } from '@/utils/event-bus' +import { defaultMailData, defaultMailItem, getMail, IMailItem, saveMail } from '@/api/mail' +import i18n from '@/lang' +import { getCoupons, ICouponData } from '@/api/coupon' +import { cloneDeep } from 'lodash' @Component({ name: 'MailEditor', components: { - MaterialInput, - Sticky, - UploadImage, - RegionPicker, - UploadCorpImage + UploadImage } }) export default class extends Vue { @@ -435,131 +238,101 @@ export default class extends Vue { } } - private activeName = 'first' - private monthDays: {id: number, label: string}[] = [] - private repeatTypes = [ - { id: 0, label: '指定日期' }, - { id: 1, label: '每日' }, - { id: 2, label: '每周' }, - { id: 3, label: '每月' }, - { id: 9, label: '随时(一般测试用)' } - ] - - private weekDays = [ - { id: 0, label: '周日' }, - { id: 1, label: '周一' }, - { id: 2, label: '周二' }, - { id: 3, label: '周三' }, - { id: 4, label: '周四' }, - { id: 5, label: '周五' }, - { id: 6, label: '周六' } - ] - - private dataRange: Date[] = [] - private selectDate: Date[] = [] - private times: string[] = [] - private selectTime: string[] = [] - - private postForm = Object.assign({}, defaultActivityData) + private postForm = Object.assign({}, defaultMailData) private loading = false - private allDepts: IShopData[] = [] - private typeOptions: {id: string, label: string, children?: any[]}[] = [] - private typeSelected: string[] = [] - private defaultProps = { - children: 'children', - label: 'label' + private rules = { + sender: [{ required: true, message: '请输入店铺', trigger: 'blur' }], + title: [{ required: true, message: '请输入邮件标题', trigger: 'blur' }], + content: [{ required: true, message: '请输入邮件内容', trigger: 'blur' }] } - private rules = { - name: [{ validator: this.validateRequire }] + private innerModalRules = { + itemId: [{ required: true, message: '请选择一个物品', trigger: 'blur' }], + count: [{ required: true, message: '请填写数量', trigger: 'blur' }] } + private allDepts = [] + private tempTagView?: ITagView + private userList = [] + + private sendDate: Date = new Date() + private endDate: Date = new Date().addDays(7) + + private innerModalVisible = false + private itemRecord = Object.assign({}, defaultMailItem) + private coupons: ICouponData[] = [] private dialogType = 'new' - private record: IRewardData = {type: 0} - private dialogVisible = false - private modalRules = { - rank: [{ required: true, message: '请输入排名', trigger: 'blur' } - ] + + get lang() { + return AppModule.language } - private coupons: ICouponData[] = [] - $refs!: { - modalForm: HTMLFormElement postForm: HTMLFormElement - typeTree: ElTree + innerModalForm: HTMLFormElement } get userLevel() { return UserModule.level } - get lang() { - return AppModule.language - } - - async created() { - this.initTimes() + created() { const id = this.$route.params?.id - await this.getRemoteCategory() - if (id) { - await this.fetchData(id) - } if (UserModule.level === 1) { - await this.getRemoteDeptList() + this.getRemoteDeptList('') EventBus.$on(EVENT_SHOP_UPDATE, () => { this.getRemoteDeptList() }) } else { - this.postForm.shop = UserModule.department - await this.fetchMyShop() + this.postForm.sender = UserModule.department + this.getUserList(this.postForm.sender) + this.getCouponList(this.postForm.sender) + } + if (id) { + this.fetchData(id) } - this.tempTagView = Object.assign({}, this.$route) - EventBus.$on(EVENT_COUPON_UPDATE, () => { - if (this.postForm.shop) { - this.getCouponList(this.postForm.shop) - } - }) } beforeDestory() { - EventBus.$off(EVENT_COUPON_UPDATE) if (UserModule.level === 1) { EventBus.$off(EVENT_SHOP_UPDATE) } } + @Watch('postForm.sender') + private shopChange(val: string) { + this.getUserList(this.postForm.sender) + this.coupons.length = 0 + this.getCouponList(this.postForm.sender) + } + + @Watch('sendDate') + private sendDateChange(val: Date) { + if (!this.endDate || this.sendDate.getTime() > this.endDate.getTime()) { + this.endDate = val.addDays(7) + } + } + private async fetchData(id: string) { try { - const { data } = await getActivity(id, { /* Your params here */ }) + const { data } = await getMail(id, { /* Your params here */ }) console.log(data) this.postForm = data - this.selectTime = [] - if (data.beginTime) { - for (const str of data.beginTime) { - this.selectTime.push(sec2TimeStr(str, false)) - } - } - this.selectDate = [] - if (data.beginDays) { - for (const sub of data.beginDays) { - this.selectDate.push(new Date(sub)) - } - } - if (data.beginDay && data.endDay) { - this.dataRange.push(new Date(data.beginDay)) - this.dataRange.push(new Date(data.endDay)) - } - // Just for test - const title = this.lang === 'zh' ? '编辑活动' : 'Edit Activity' + const title = this.lang === 'zh' ? '编辑邮件' : 'Edit Mail' // Set tagsview title this.setTagsViewTitle(title) // Set page title this.setPageTitle(title) + if (data.sendTime !== undefined) { + this.sendDate = new Date(data.sendTime) + } + if (data.endTime !== undefined) { + this.endDate = new Date(data.endTime) + } } catch (err) { console.error(err) } @@ -580,31 +353,46 @@ export default class extends Vue { private async submitForm() { try { await this.$refs.postForm.validate() - const times = [] - for (const str of this.selectTime) { - times.push(timeStr2Sec(str)) + if (!this.sendDate) { + this.$message({ + message: '请指定发送时间', + type: 'error' + }) + return false } - this.postForm.beginTime = times - this.postForm.beginDays.length = 0 - for (const d of this.selectDate) { - this.postForm.beginDays.push(d.getTime()) + if (!this.postForm.sender) { + this.$message({ + message: `请选择一个${i18n.tc('main.shop')}`, + type: 'error' + }) + return false } - if (this.dataRange.length > 1) { - this.postForm.beginDay = this.dataRange[0].getTime() - this.postForm.endDay = this.dataRange[1].getTime() + if (this.postForm.type === 0 && this.postForm.accounts.length === 0) { + this.$message({ + message: '请指定收件人', + type: 'error' + }) + return false + } + this.postForm.senderShop = this.getShopName(this.postForm.sender) + if (this.postForm.type === 1) { + this.postForm.shops = [this.postForm.sender] } - this.postForm.qtypes = this.$refs.typeTree.getCheckedKeys() this.loading = true - const { data } = await saveActivity(this.postForm) + this.postForm.sendTime = this.sendDate.getTime() + if (this.endDate) { + this.postForm.endTime = this.endDate.getTime() + } + const { data } = await saveMail(this.postForm) this.postForm = data this.loading = false this.$notify({ title: 'Success', - message: 'The post save successfully', + message: '邮件保存成功', type: 'success', duration: 2000 }) - EventBus.$emit(EVENT_ACTIVITY_UPDATE, {}) + EventBus.$emit(EVENT_COUPON_UPDATE, {}) } catch (err) { console.error('Submit Error!') return false @@ -613,7 +401,7 @@ export default class extends Vue { private async onCancel() { try { - await this.$confirm('确认不保存当前活动信息?', 'Warning', { + await this.$confirm('确认不保存当前信息?', 'Warning', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' @@ -625,207 +413,72 @@ export default class extends Vue { } } - private async getRemoteDeptList() { - const { data } = await getShops({}) + private async getRemoteDeptList(name?: string) { + const { data } = await getShops({ key: name }) if (!data.records) return this.allDepts = data.records } - private async fetchMyShop() { - const { data } = await getMyShop() - this.typeSelected = data.qtypes - console.log(this.typeSelected) - this.$refs.typeTree.setCheckedKeys(this.typeSelected) - } - - private dataChange(_: any) { - console.log(this.selectDate) - } - - private initTimes() { - for (let i = 0; i < 24; i++) { - for (let j = 0; j < 4; j++) { - const secs = i * 3600 + j * 15 * 60 - const label = sec2TimeStr(secs, false) - this.times.push(label) + private getShopName(shop: string) { + for (const _d of this.allDepts) { + if (_d._id === shop) { + return _d.name } } - this.monthDays.push({ id: 0, label: '全选' }) - for (let i = 1; i < 32; i++) { - this.monthDays.push({ id: i, label: i + '' }) - } + return '' } - private timeChange(vals: string[]) { - if (vals.length > 0) { - let lastVal = this.selectTime[this.selectTime.length - 1] - if (!/^\d{1,2}:\d{1,2}$/.test(lastVal)) { - this.selectTime.pop() - } - lastVal = sec2TimeStr(timeStr2Sec(lastVal), false) - this.selectTime.splice(this.selectTime.length - 1, 1, lastVal) - console.log(this.selectTime) - } + private async getUserList(shop: string) { + const { data } = await getShopUsers({ shop }) + this.userList = data } - private monthDaysChange(days: number[]) { - if (days.indexOf(0) >= 0) { - this.postForm.monthDays.length = 0 - for (let i = 1; i < 32; i++) { - this.postForm.monthDays.push(i) - } - } - } - - @Watch('postForm.shop') - private onShopChange() { - if (this.postForm.shop) { - this.getCouponList(this.postForm.shop) - } - - if (this.postForm.qtypes?.length > 0) { - this.typeSelected = this.postForm.qtypes - } else if (this.postForm.shop) { - let currentShop - for (const p of this.allDepts) { - if (p._id === this.postForm.shop) { - currentShop = p - break - } - } - if (currentShop) { - this.typeSelected = currentShop.qtypes - } else { - this.typeSelected = [] - } - } - this.$refs.typeTree.setCheckedKeys(this.typeSelected) - } - - // begin of set puzzle types - private async getRemoteCategory() { - const { data } = await getAllCategory() - for (const cat of data) { - const subArr = [] - for (const s of cat.children) { - subArr.push({ - id: s._id, - label: s.name - }) - } - this.typeOptions.push({ - id: cat._id, - label: cat.name, - children: subArr - }) - } - } - - // begin of award list private async getCouponList(shop: string) { const { data } = await getCoupons({ shop }) this.coupons = data.records + this.coupons.unshift({ _id: 'lottery_ticket', name: '抽奖券' }) } - private formatCoupon(row: number, column: number, cellValue: string, index: number) { - let result = `未知(${cellValue})` - const data = this.postForm.rewardInfo[index] - for (const dep of this.coupons) { - if (dep._id === cellValue) { - result = dep.name - break - } - } - return `${result} x ${data.count}` + private filterMethod(query: string, item: any) { + return item.nickname.indexOf(query) > -1 } - private formatRank(row: number, column: number, cellValue: string, index: number) { - const data = this.postForm.rewardInfo[index] - let result = `第 ${data.rank} 名` - if (data.rankEnd) { - result = `第 ${data.rank} 至 ${data.rankEnd} 名` - } - return result - } - - private async deleteRank(scope: any) { - const { $index } = scope - try { - await this.$confirm('Confirm to remove the record?', 'Warning', { - confirmButtonText: 'Confirm', - cancelButtonText: 'Cancel', - type: 'warning' - }) - this.postForm.rewardInfo.splice($index, 1) - this.$message({ - type: 'success', - message: '删除成功, 请点击保存' - }) - } catch (err) { - - } - } - - private handleCreateReward() { - this.record = Object.assign({}, defaultRewardData) - this.record.id = this.postForm.rewardInfo.length - this.dialogType = 'new' - this.dialogVisible = true - } - - private handleEdit(scope: any) { + private editItem(index: number, data: IMailItem) { this.dialogType = 'edit' - this.dialogVisible = true - this.record = cloneDeep(scope.row) + this.itemRecord = cloneDeep(data) + this.itemRecord.index = index + this.innerModalVisible = true } - private closeModal() { - this.dialogVisible = false - this.$refs.modalForm.clearValidate() + private delItem(index: number) { + this.postForm.items.splice(index, 1) } - private saveReward() { - const isEdit = this.dialogType === 'edit'; - (this.$refs.modalForm as HTMLFormElement).validate(async(valid: boolean) => { - if (!valid) { - this.$message.error('请按要求填写表单') - return false - } - if (isEdit) { - for (let index = 0; index < this.postForm.rewardInfo.length; index++) { - if (this.postForm.rewardInfo[index].id === this.record.id) { - this.postForm.rewardInfo.splice(index, 1, Object.assign({}, this.record)) - break - } + private addItem() { + this.dialogType = 'new' + this.itemRecord = Object.assign({ index: this.postForm.items.length }, defaultMailItem) + this.innerModalVisible = true + } + + // begin of modal + private closeInnerModal() { + this.innerModalVisible = false + } + + private async saveItem() { + try { + await this.$refs.innerModalForm.validate() + for (const _d of this.coupons) { + if (this.itemRecord.itemId === _d._id) { + this.itemRecord.name = _d.name + break } - } else { - this.postForm.rewardInfo.push(this.record) } - this.dialogVisible = false - this.$notify({ - title: 'Success', - dangerouslyUseHTMLString: true, - message: ` - 奖励成功保存, 请点击保存 - `, - type: 'success' - }) - }) - } - - private iconUploadSuccess(imgUrl: string) { - console.log('upload icon success: ' + imgUrl) - this.postForm.icon = imgUrl - this.$forceUpdate() - } - - private bannerUploadSuccess(imgUrl: string) { - console.log('upload banner success: ' + imgUrl) - this.postForm.banner = imgUrl - this.$forceUpdate() + this.postForm.items.splice(this.itemRecord.index, 1, Object.assign({}, this.itemRecord)) + } catch (err) { + console.log(err) + } + this.innerModalVisible = false } } - - diff --git a/src/views/mail/list.vue b/src/views/mail/list.vue index 9c80314..f317bec 100644 --- a/src/views/mail/list.vue +++ b/src/views/mail/list.vue @@ -7,9 +7,9 @@ @@ -26,11 +26,11 @@ 重置 - + 添加 @@ -54,33 +54,53 @@ + + + + + + + + + - + -