增加邮件相关接口

This commit is contained in:
zhl 2021-06-08 17:30:02 +08:00
parent 446d962fd8
commit b8f5c94960
4 changed files with 352 additions and 2 deletions

View File

@ -643,4 +643,96 @@
geted: 0, // 是否已获得, 0: 未获得, 1: 已获得
}
]
```
```
### 17. 邮件列表
1. Method: POST
2. <span id="215">URI: /api/:accountid/mails</span>
| 字段 | 说明 |
| -------- | -------------------------------------- |
| accountid | 帐号id |
> POST参数
| 字段 | 说明 |
| -------- | -------------------------------------- |
| sid | 店铺id |
3. Response: JSON
```js
[{
_id: '邮件id',
title: '邮件标题',
content: 1: '邮件正文'
status: 0, // 邮件状态: 0: 未读 1: 已读, 2: 已领取附件
items: [{
itemId: '物品的id'
name: '物品名',
count: 1 // 数量
}]
}]
```
### 18. 设置邮件已读
1. Method: POST
2. <span id="215">URI: /api/:accountid/mail/read</span>
| 字段 | 说明 |
| -------- | -------------------------------------- |
| accountid | 帐号id |
> POST参数
| 字段 | 说明 |
| -------- | -------------------------------------- |
| ids | 邮件id数组 |
### 19. 领取邮件附件
1. Method: POST
2. <span id="215">URI: /api/:accountid/mail/attachment</span>
| 字段 | 说明 |
| -------- | -------------------------------------- |
| accountid | 帐号id |
> POST参数
| 字段 | 说明 |
| -------- | -------------------------------------- |
| ids | 邮件id数组 |
3. Response: JSON
```js
[{ // 获得的物品列表
coupon: '优惠券的id',
name: '优惠券名',
count: 1, //数量
couponUrl: '优惠券详情图的url',
rewardType: 0, // 0: 优惠券, 1: 抽奖券
}]
```
### 20. 删除邮件
1. Method: POST
2. <span id="215">URI: /api/:accountid/mail/delete</span>
| 字段 | 说明 |
| -------- | -------------------------------------- |
| accountid | 帐号id |
> POST参数
| 字段 | 说明 |
| -------- | -------------------------------------- |
| ids | 邮件id数组 |

View File

@ -0,0 +1,83 @@
import BaseController from '../../common/base.controller'
import { role, router } from '../../decorators/router'
import { UserMail } from '../../models/user/UserMail'
import { SysMail } from '../../models/content/SysMail'
import { ZError } from '../../common/ZError'
import { UserReward } from '../../models/user/UserReward'
class MailController extends BaseController {
@role('anon')
@router('post /api/:accountId/mails')
async list(req: any) {
const { accountId, sid } = req.params
await UserMail.updateExpire(accountId)
let mails = await UserMail.find({ accountId, deleted: false }).sort({ status: 1, _id: -1 })
let mailSet: Set<string> = new Set()
for (let mail of mails) {
mailSet.add(mail.oid)
}
let sysMails = await SysMail.findMail(accountId, sid, [...mailSet])
if (sysMails?.length > 0) {
for (let _m of sysMails) {
let mail = await UserMail.receiveOne(accountId, _m)
mails.push(mail)
}
}
return mails.map(o => o.toJson())
}
@role('anon')
@router('post /api/:accountId/mail/delete')
async delete(req: any) {
const { accountId, ids } = req.params
if (!ids || !Array.isArray(ids) || ids.length === 0) {
throw new ZError(10, 'ids必须是一个数组')
}
let result = await UserMail.deleteMails(accountId, ids)
return {}
}
@role('anon')
@router('post /api/:accountId/mail/read')
async read(req: any) {
const { accountId, ids } = req.params
if (!ids || !Array.isArray(ids) || ids.length === 0) {
throw new ZError(10, 'ids必须是一个数组')
}
await UserMail.updateMails(accountId, ids, 1)
return {}
}
@role('anon')
@router('post /api/:accountId/mail/attachment')
async attachment(req: any) {
const { accountId, ids } = req.params
if (!ids || !Array.isArray(ids) || ids.length === 0) {
throw new ZError(10, 'ids必须是一个数组')
}
let mails = await UserMail.find({ _id: { $in: ids }, deleted: false, accountId, status: { $lt: 2 } })
if (!mails || mails.length === 0) {
throw new ZError(11, '未找到符合条件的邮件')
}
let results = []
for (let mail of mails) {
if (mail.items && mail.items.length > 0) {
for (let item of mail.items) {
let record = await UserReward.saveOneRecord({
accountId,
shop: mail.senderShop,
itemId: item.itemId,
count: item.count,
rewardId: mail._id + '',
activityId: mail.oid + '',
source: 'mail',
})
results.push(record)
}
mail.status = 2
await mail.save()
}
}
return results
}
}

View File

@ -1,18 +1,99 @@
import { dbconn } from '../../decorators/dbconn'
import { getModelForClass, modelOptions, prop } from '@typegoose/typegoose'
import { getModelForClass, index, modelOptions, prop } from '@typegoose/typegoose'
import { Severity } from '@typegoose/typegoose/lib/internal/constants'
import { BaseModule } from '../Base'
import { noJson } from '../../decorators/nojson'
export class MailItemClass {
@prop()
public itemId: string
@prop()
public name: string
@prop()
public count: number
}
@dbconn()
@index({ accounts: 1, deleted: 1, type: 1, sendTime: 1, endTime: 1 }, { unique: false })
@index({ shops: 1, deleted: 1, type: 1, sendTime: 1, endTime: 1 }, { unique: false })
@modelOptions({
schemaOptions: { collection: 'sys_mail', timestamps: true },
options: { allowMixed: Severity.ALLOW },
})
export class SysMailClass extends BaseModule {
@prop()
public sender: string
@prop()
public senderShop: string
@prop()
public title: string
@prop()
public content: string
/**
*
* @type {number} 0: 普通邮件 1: 店铺群发
*/
@prop({ default: 0 })
public type: number
@prop({ type: () => [String] })
public accounts: string[]
@prop({ type: () => [String] })
public shops: string[]
@prop({ type: () => [MailItemClass] })
public items: MailItemClass[]
/**
*
* @type {boolean}
*/
@noJson()
@prop({ default: false })
public deleted: boolean
@noJson()
@prop()
public deleteTime: Date
/**
*
* @type {string}
*/
@prop()
public createdBy: string
@prop()
public sendTime: number
@prop()
public endTime: number
public static async findMail(accountId: string, shop: string, excludes: string[]) {
let now = Date.now()
let mails0 = await SysMail.find({
accounts: accountId,
type: 0,
deleted: false,
sendTime: { $lte: now },
endTime: { $gte: now },
_id: { $nin: excludes },
})
let mails1 = await SysMail.find({
shops: shop,
type: 1,
deleted: false,
sendTime: { $lte: now },
endTime: { $gte: now },
_id: { $nin: excludes },
})
return mails0.concat(mails1)
}
}
export const SysMail = getModelForClass(SysMailClass, { existingConnection: SysMailClass.db })

View File

@ -0,0 +1,94 @@
import { dbconn } from '../../decorators/dbconn'
import { getModelForClass, index, modelOptions, prop } from '@typegoose/typegoose'
import { Severity } from '@typegoose/typegoose/lib/internal/constants'
import { BaseModule } from '../Base'
import { MailItemClass } from '../content/SysMail'
import { noJson } from '../../decorators/nojson'
@dbconn()
@index({ accountId: 1, oid: 1 }, { unique: true })
@index({ accountId: 1, deleted: 1, status: 1 }, { unique: false })
@modelOptions({
schemaOptions: { collection: 'user_mail', timestamps: true },
options: { allowMixed: Severity.ALLOW },
})
export class UserMailClass extends BaseModule {
@prop()
public oid: string
@prop()
public sender: string
@prop()
public senderShop: string
@prop()
public title: string
@prop()
public content: string
@prop()
public accountId: string
@prop({ type: () => [MailItemClass] })
public items: MailItemClass[]
/**
*
* @type {number} 0: 未读 1: 已读, 2: 已领取附件
*/
@prop({ default: 0 })
public status: number
/**
*
* @type {number}
*/
@prop()
public expire: number
/**
*
* @type {boolean}
*/
@noJson()
@prop({ default: false })
public deleted: boolean
@noJson()
@prop()
public deleteTime: Date
public static async receiveOne(accountId: string, mail: any) {
let record = new UserMail({})
record.oid = mail.id
record.title = mail.title
record.content = mail.content
record.accountId = accountId
record.items = mail.items
record.sender = mail.sender
record.senderShop = mail.senderShop
record.expire = Date.now() + 3600 * 24 * 15 * 1000
await record.save()
return record
}
public static async updateExpire(accountId: string) {
await UserMail.updateMany(
{ accountId, deleted: false, expire: { $lt: Date.now() } },
{ $set: { deleted: true, deleteTime: new Date() } },
)
}
public static async deleteMails(accountId: string, ids: string[]) {
return UserMail.updateMany(
{ accountId, deleted: false, _id: { $in: ids } },
{ $set: { deleted: true, deleteTime: new Date() } },
)
}
public static async updateMails(accountId: string, ids: string[], status: number) {
return UserMail.updateMany({ accountId, deleted: false, _id: { $in: ids } }, { $set: { status: status } })
}
}
export const UserMail = getModelForClass(UserMailClass, { existingConnection: UserMailClass.db })