增加邮件相关接口
This commit is contained in:
parent
446d962fd8
commit
b8f5c94960
94
doc/api.md
94
doc/api.md
@ -643,4 +643,96 @@
|
|||||||
geted: 0, // 是否已获得, 0: 未获得, 1: 已获得
|
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数组 |
|
||||||
|
83
src/api/controllers/mail.controller.ts
Normal file
83
src/api/controllers/mail.controller.ts
Normal 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
|
||||||
|
}
|
||||||
|
}
|
@ -1,18 +1,99 @@
|
|||||||
import { dbconn } from '../../decorators/dbconn'
|
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 { Severity } from '@typegoose/typegoose/lib/internal/constants'
|
||||||
import { BaseModule } from '../Base'
|
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()
|
@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({
|
@modelOptions({
|
||||||
schemaOptions: { collection: 'sys_mail', timestamps: true },
|
schemaOptions: { collection: 'sys_mail', timestamps: true },
|
||||||
options: { allowMixed: Severity.ALLOW },
|
options: { allowMixed: Severity.ALLOW },
|
||||||
})
|
})
|
||||||
export class SysMailClass extends BaseModule {
|
export class SysMailClass extends BaseModule {
|
||||||
|
@prop()
|
||||||
|
public sender: string
|
||||||
|
|
||||||
|
@prop()
|
||||||
|
public senderShop: string
|
||||||
|
|
||||||
@prop()
|
@prop()
|
||||||
public title: string
|
public title: string
|
||||||
|
|
||||||
@prop()
|
@prop()
|
||||||
public content: string
|
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 })
|
export const SysMail = getModelForClass(SysMailClass, { existingConnection: SysMailClass.db })
|
||||||
|
94
src/models/user/UserMail.ts
Normal file
94
src/models/user/UserMail.ts
Normal 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 })
|
Loading…
x
Reference in New Issue
Block a user