diff --git a/game-server/app/servers/gm/handler/gmHandler.ts b/game-server/app/servers/gm/handler/gmHandler.ts index a2a892ba7..2d86ab292 100644 --- a/game-server/app/servers/gm/handler/gmHandler.ts +++ b/game-server/app/servers/gm/handler/gmHandler.ts @@ -13,7 +13,7 @@ import { taflush } from '../../../services/sdkService'; import { ActivityInRemote } from '../../../domain/activityField/activityField'; import { pushCurrentTime } from '../../../services/auctionService'; import { SurveyModel, SurveyUpdate } from '../../../db/Survery'; -import { getSurvey } from '../../../services/gmService'; +import { compaireMailGoods, getSurvey } from '../../../services/gmService'; import { sendMessageToAllWithSuc } from '../../../services/pushService'; import { sendMailByContent, sendMailsByGmMail } from '../../../services/mailService'; import { saveMemory } from '../../../services/log/memoryLogService'; @@ -69,13 +69,28 @@ export class GmHandler { //对接gm后台,下发邮件 async sendMail(gmmail: GMMailType, isPass: boolean, uid: number) { let id = gmmail._id; - let { receivers, mailType, status, timeType, startTime, circleHour, circleDay } = gmmail; + let { receivers, mailType, status, hasGoods, goods } = gmmail; if(status != GM_MAIL_STATUS.CREATE) { return resResult(STATUS.GM_MAIL_HAS_SENT); } if(isPass) { - await sendMailsByGmMail([gmmail]); + let gmmailArr: GMMailType[] = []; + if(mailType == GM_MAIL_TYPE.SINGLE && hasGoods && (!goods || goods.length == 0)) { + for(let receiver of receivers) { + let index = gmmailArr.findIndex(gmmail => compaireMailGoods(gmmail, receiver)); + if(index == -1) { + gmmailArr.push({...gmmail, receivers: [receiver], goods: receiver.rewards, hasGoods: receiver?receiver.rewards.length > 0: false }); + } else { + gmmailArr[index].receivers.push(receiver); + } + } + } else { + gmmailArr.push(gmmail); + } + + + await sendMailsByGmMail(gmmailArr); } await GMMailModel.updateMailById(id, { status: isPass? GM_MAIL_STATUS.PASS: GM_MAIL_STATUS.NOT_PASS, viewAt: new Date(), viewBy: uid }, uid); return resResult(STATUS.SUCCESS); diff --git a/game-server/app/services/gmService.ts b/game-server/app/services/gmService.ts index cc90168e5..79fe282a0 100644 --- a/game-server/app/services/gmService.ts +++ b/game-server/app/services/gmService.ts @@ -6,7 +6,7 @@ import { GroupMessageType } from "../db/GroupMessage"; import { pinus } from "pinus"; import { ServerlistModel, ServerlistType } from "../db/Serverlist"; import { sendMailsByGmMail } from "./mailService"; -import GMMail, { GMMailModel } from '../db/GMMail'; +import GMMail, { GMMailModel, GMMailType, Receiver } from '../db/GMMail'; import { getPastTime, nowSeconds } from "../pubUtils/timeUtil"; import { CreateServerParam } from "../domain/backEndField/params"; import { SignInData } from "../domain/activityField/signInField"; @@ -385,4 +385,19 @@ export async function calHiddenData(uid: number) { } } await HiddenDataModel.updateHiddenData(getPastTime(), heroes, goods, uid); +} + +export function compaireMailGoods(gmmail: GMMailType, receiver: Receiver) { + if(gmmail.hasGoods == false && (!receiver.rewards || receiver.rewards.length)) return true; + let tmpGoods = gmmail.goods||[]; + let receiverGoods = receiver.rewards||[]; + + if(tmpGoods.length != receiverGoods.length) return false; + tmpGoods.sort((a, b) => a.id - b.id); + receiverGoods.sort((a, b) => a.id - b.id); + for(let i = 0; i < tmpGoods.length; i++) { + if(!receiverGoods[i]) return false; + if(tmpGoods[i].id != receiverGoods[i].id || tmpGoods[i].count != receiverGoods[i].count) return false; + } + return true } \ No newline at end of file diff --git a/gm-server/app/controller/mail.ts b/gm-server/app/controller/mail.ts index 0695c5155..f88769a33 100644 --- a/gm-server/app/controller/mail.ts +++ b/gm-server/app/controller/mail.ts @@ -47,6 +47,16 @@ export default class MailController extends Controller { public async updateGMMail() { const { ctx } = this; const msg = ctx.request.body; + if(msg.receivers && msg.receivers.length > 0) { + try { + for(let receiver of msg.receivers) { + if(receiver.rewards) receiver.rewards = JSON.parse(receiver.rewards); + } + } catch(e) { + return ctx.body = ctx.service.utils.resResult(STATUS.WRONG_PARMS); + } + } + let params = new UpdateMailParams(msg); let check = params.checkParams(); if(!check) return ctx.body = ctx.service.utils.resResult(STATUS.WRONG_PARMS); diff --git a/gm-server/app/controller/upload.ts b/gm-server/app/controller/upload.ts index 5d011b8f1..bfd18e660 100644 --- a/gm-server/app/controller/upload.ts +++ b/gm-server/app/controller/upload.ts @@ -1,8 +1,8 @@ -import { Controller } from 'egg'; +import { Controller, FileStream } from 'egg'; import { Stream } from 'stream'; import { STATUS } from '@consts'; - const fs = require('fs'); - const path = require('path'); +const fs = require('fs'); +const path = require('path'); const unzip = require("unzip-stream"); const temp = require('temp'); const compressing = require("compressing"); @@ -12,21 +12,25 @@ const pump = require('mz-modules/pump'); const folderName = 'hot_update_files'; const hotUpdateAddr = `/root/${folderName}`; const publishPath = '/root/hot_update_backup'; -import {exec} from 'child_process' -import { reloadResources } from '@pubUtils/data'; -import { decodeArrayStr } from '@pubUtils/util'; +import { exec } from 'child_process' +import { gameData, reloadResources } from '@pubUtils/data'; +import { decodeArrayStr, genCode, parseGoodStr } from '@pubUtils/util'; import { getLocalImgUrl, getLocalQrCodeUrl, getRemoteImgUrl, getRemoteQrCodeUrl } from '@pubUtils/battleUtils'; +import { RewardInter } from '@pubUtils/interface'; +import { RoleModel } from '@db/Role'; +import { isNumber, isString } from 'util'; const sendToWormhole = require('stream-wormhole'); +const XLSX = require('xlsx'); export default class UploadController extends Controller { - private deleteFolder (path) { + private deleteFolder(path) { let files = []; - if( fs.existsSync(path) ) { + if (fs.existsSync(path)) { files = fs.readdirSync(path); - files.forEach((file) =>{ + files.forEach((file) => { let curPath = path + "/" + file; - if(fs.statSync(curPath).isDirectory()) { + if (fs.statSync(curPath).isDirectory()) { this.deleteFolder(curPath); } else { fs.unlinkSync(curPath); @@ -37,303 +41,368 @@ export default class UploadController extends Controller { } - private getFileList (p: string, resultArr: Array<{path:string,name:string}>) { - console.log(p, fs.existsSync(p)) - if( fs.existsSync(p) ) { - let files = fs.readdirSync(p); - console.log(p, files, resultArr); - files.forEach((file) =>{ - let curPath = p + "/" + file; - // console.log(curPath, fs.statSync(curPath).isDirectory()) - if(fs.statSync(curPath).isDirectory()) { - this.getFileList(curPath, resultArr); - } else { - resultArr.push({ - path: curPath, - name: file - }); - } - }); + private getFileList(p: string, resultArr: Array<{ path: string, name: string }>) { + console.log(p, fs.existsSync(p)) + if (fs.existsSync(p)) { + let files = fs.readdirSync(p); + console.log(p, files, resultArr); + files.forEach((file) => { + let curPath = p + "/" + file; + // console.log(curPath, fs.statSync(curPath).isDirectory()) + if (fs.statSync(curPath).isDirectory()) { + this.getFileList(curPath, resultArr); + } else { + resultArr.push({ + path: curPath, + name: file + }); + } + }); + } } - } - public async upload() { - const { ctx } = this; - const stream = await ctx.getFileStream(); - // const filename = stream.filename; - // const target = path.join(url, filename); + public async upload() { + const { ctx } = this; + const stream = await ctx.getFileStream(); + // const filename = stream.filename; + // const target = path.join(url, filename); + + // const writeStream = fs.createWriteStream(target); + if (stream.mimeType == 'application/zip') { + try { + + let dirPath = await temp.mkdir(folderName); // 临时文件夹 + + // 解压上传文件的stream + await this.doUnzipExtra(stream, dirPath); + + console.log('读取文件'); + let files: any = fs.readdirSync(dirPath); + let msg = '', result = ''; + for (let file of files) { + let flag = false; + + let arr = ['project.manifest', 'version.manifest', 'assets', 'src']; + for (let fileName of arr) { + console.log(`${dirPath}/${file}/${fileName}`); + let result = fs.existsSync(`${dirPath}/${file}/${fileName}`); + if (!result) { + msg = '缺少文件' + fileName; + flag = true; + break; + } + } + if (flag) { + continue; + } else { + result = file; + dirPath += `/${file}`; + }; + } + if (!result) { + throw new Error(msg); + } + + // 历史记录压缩移动 + console.log('历史记录压缩移动'); + let isEmpty = true; + try { + let oldFiles: any = fs.readdirSync(hotUpdateAddr); + console.log(oldFiles.length); + isEmpty = oldFiles.length <= 0; + } catch (e) { + isEmpty = true; + } + if (!isEmpty) { + await compressing.zip.compressDir(hotUpdateAddr, `${dirPath}/${folderName}.zip`); + if (!fs.existsSync(publishPath)) { + fs.mkdirSync(publishPath); + } + let versionManifest: string = ''; + try { + let version = JSON.parse(fs.readFileSync(`${hotUpdateAddr}/version.manifest`)); + versionManifest = version.version; + } catch (e) { + console.log(e); + } + fs.renameSync(`${dirPath}/${folderName}.zip`, `${publishPath}/${folderName}_${versionManifest}_${moment().format('YYMMDDHHmmss')}.zip`); + + // 删除原始文件 + this.deleteFolder(hotUpdateAddr); + } + + // 保存新文件 + console.log('保存至热更新地址'); + fs.renameSync(dirPath, hotUpdateAddr); + + temp.cleanupSync(); + return ctx.body = ctx.service.utils.resResult(STATUS.SUCCESS); + + } catch (err) { + console.log(err) + return ctx.body = ctx.service.utils.resResult(STATUS.GM_UPLOAD_FORMAT_ERR, null, err.message); + } + + } else { + return ctx.body = ctx.service.utils.resResult(STATUS.GM_UPLOAD_FORMAT_ERR); + } + } + + private async doUnzipExtra(stream: Stream, dirPath: string) { + return new Promise((resolve, reject) => { + // 解压上传文件的stream + var unzipExtractor = unzip.Extract({ path: dirPath }); + unzipExtractor.on('close', function () { + resolve(null); + }); + + unzipExtractor.on('close', function (e) { + reject(e); + }); + + stream.pipe(unzipExtractor); // 异步写入文件 + }) + } + + private jsonFolder = '/app/resource/jsons'; + private warjsonFolder = '/app/resource/warJsons'; + private tsFolder = '/app/pubUtils'; + + private distJsonFolder = `/../game-server/dist${this.jsonFolder}`; + private distWarjsonFolder = `/../game-server/dist${this.warjsonFolder}`; + private distTsFolder = `/../game-server/dist${this.tsFolder}`; + + public async uploadJson() { + const { ctx } = this; + + + const parts = ctx.multipart({}); + const files = []; + + try { + let stream; + let writeStream; + + while ((stream = await parts()) != null) { + console.log('******', stream); + const filename = stream.filename; + let filenameWithoutEx = filename ? filename.split('.')[0] : ''; + if (stream.mimeType == 'application/json') { + if (filenameWithoutEx.match(/^\d{1,}$/)) { + let target1 = path.join(this.config.baseDir, this.warjsonFolder, filename); + let target2 = path.join(this.config.baseDir, this.distWarjsonFolder, filename); + writeStream = fs.createWriteStream(target1); + await pump(stream, writeStream); + fs.copyFileSync(target1, target2); + files.push(filename); + } else { + let target1 = path.join(this.config.baseDir, this.jsonFolder, filename); + let target2 = path.join(this.config.baseDir, this.distJsonFolder, filename); + writeStream = fs.createWriteStream(target1); + await pump(stream, writeStream); + fs.copyFileSync(target1, target2); + files.push(filename); + } + } else if (stream.mimeType == 'application/octet-stream') { + let target1 = path.join(this.config.baseDir, this.tsFolder, 'dicParam.js'); + let target2 = path.join(this.config.baseDir, this.distTsFolder, filename); + writeStream = fs.createWriteStream(target1); + await pump(stream, writeStream); + fs.copyFileSync(target1, target2); + files.push(filename); + } + + let envs = decodeArrayStr(ctx.request.headers.env || '', ','); + + if (envs.length > 0) { // 转发 + for (let env of envs) { + if (env == ctx.app.config.realEnv) continue; + await ctx.service.utils.transmit(env, ctx.request.url, writeStream); + } + } + sendToWormhole(stream); + } + + } catch (e) { + console.error(e); + } + + return ctx.body = ctx.service.utils.resResult(STATUS.SUCCESS, { + "files": files + }); + + // console.log('****', stream); + // // const filename = stream.filename; + // // const target = path.join(url, filename); + + // if(stream.mimeType == 'application/zip') { + // try { + // let dirPath = await temp.mkdir(this.jsonFolderName); // 临时文件夹 + + // console.log('读取文件'); + // await this.doUnzipExtra(stream, dirPath); + // let files = new Array<{path:string,name:string}>(); + // this.getFileList(dirPath, files); + // console.log(files); + + // console.log('保存文件'); + // if (!fs.existsSync(this.jsonFolderPath)) { + // fs.mkdirSync(this.jsonFolderPath); + // } + // for (let {path, name} of files) { + // console.log(`${this.jsonFolderPath}/${name}`); + // fs.renameSync(path, `${this.jsonFolderPath}/${name}`); + // } + + // temp.cleanupSync(); + // return ctx.body = ctx.service.utils.resResult(STATUS.SUCCESS, { + // "files": JSON.stringify(files) + // }); + // } catch (err) { + // console.log(err) + // return ctx.body = ctx.service.utils.resResult(STATUS.INTERNAL_ERR); + // } + + // } else { + // return ctx.body = ctx.service.utils.resResult(STATUS.GM_UPLOAD_FORMAT_ERR); + // } + } + + public async reloadResource() { + const { ctx } = this; - // const writeStream = fs.createWriteStream(target); - if(stream.mimeType == 'application/zip') { try { - let dirPath = await temp.mkdir(folderName); // 临时文件夹 + reloadResources(); + ctx.body = ctx.service.utils.resResult(STATUS.SUCCESS, { isOK: true }); + return; + } catch (e) { + ctx.body = ctx.service.utils.resResult(STATUS.SUCCESS, { isOK: false, err: e.stack }); + return; + } + } - // 解压上传文件的stream - await this.doUnzipExtra(stream, dirPath); + public async uploadQrCode() { + const { ctx } = this; - console.log('读取文件'); - let files:any = fs.readdirSync(dirPath); - let msg = '', result = ''; - for(let file of files) { - let flag = false; - - let arr = ['project.manifest', 'version.manifest', 'assets', 'src']; - for(let fileName of arr) { - console.log(`${dirPath}/${file}/${fileName}`); - let result = fs.existsSync(`${dirPath}/${file}/${fileName}`); - if(!result) { - msg = '缺少文件' + fileName; - flag = true; + try { + const { ctx } = this; + const parts = ctx.multipart(); + let part, env = ctx.request.headers.env, type = ctx.request.headers.type, fileName = '', writePath = '', ext = '', remoteUrl = ''; + while ((part = await parts()) != null) { + if (part.length) { + console.log('kv: ', `${part[0]}: ${part[1]}`); + } else { + if (!part.filename) continue; + + let filenames = part.filename.split('.'); + ext = filenames[filenames.length - 1]; + if (type == 'popNotice' || type == 'loginPage' || type == 'loadingPage' || type == 'icon') { + writePath = getLocalImgUrl(this.app.config.realEnv, type); + fileName = `${moment().valueOf()}.${ext}`; + remoteUrl = getRemoteImgUrl(this.app.config.realEnv, fileName, type); + } else { + writePath = getLocalQrCodeUrl(this.app.config.realEnv, env); + fileName = `QR${moment().valueOf()}.${ext}`; + remoteUrl = getRemoteQrCodeUrl(env, fileName); + } + + let fullPath = `${writePath}/${fileName}`; + try { + fs.accessSync(writePath); + } catch (err) { + if (err) { + fs.mkdirSync(writePath, { recursive: true }); + } + } + if (!fs.existsSync(fullPath)) { + fs.writeFileSync(fullPath, ''); + } + const writeStream = fs.createWriteStream(fullPath); + await pump(part, writeStream); + + // remoteUrl = `${getRemoteRplUrl(ctx.app.config.realEnv, roleId, warType, battleCode)}/${battleCode}.bin`; + } + await sendToWormhole(part); + } + ctx.body = ctx.service.utils.resResult(STATUS.SUCCESS, { isOK: true, url: remoteUrl, ext }); + return; + } catch (e) { + ctx.body = ctx.service.utils.resResult(STATUS.SUCCESS, { isOK: false, err: e.stack }); + return; + } + } + + public async uploadMailExcel() { + const { ctx } = this; + + try { + const { ctx } = this; + const stream = await ctx.getFileStream(); + let exceldata = await this.streamToExcekData(stream); + + let result: { code: string, env: string, serverId: number, roleId: string, roleName: string, rewards: string, isError: boolean, isNameError: boolean, isRewardError: boolean }[] = []; + for(let i = 1; i < exceldata.length; i++) { + let data = exceldata[i]; + let newObj = { code: genCode(5), env: ctx.app.config.realEnv, serverId: data.serverId, roleId: data.roleId, roleName: '', rewards: '', isError: true, isNameError: true, isRewardError: true }; + if(data.roleId && isString(data.roleId)) { + let role = await RoleModel.findByRoleId(data.roleId, 'roleName serverId'); + if(role && role.serverId == data.serverId) { + newObj.roleName = role.roleName; + newObj.serverId = role.serverId; + newObj.isNameError = false; + } + } + if(data.rewards && isString(data.rewards)) { + try { + let rewards: RewardInter[] = parseGoodStr(data.rewards); + let isRewardError = false; + for(let { id, count } of rewards) { + let dicGoods = gameData.goods.get(id); + if(!dicGoods) { isRewardError = true; break; } + if(!isNumber(count) || count <= 0) { isRewardError = true; break; } + } + newObj.rewards = JSON.stringify(rewards); + newObj.isRewardError = isRewardError; + } catch(e) { + console.log('updateMailExcel', e) + } + } + newObj.isError = newObj.isNameError || newObj.isRewardError; + result.push(newObj); + } + + ctx.body = ctx.service.utils.resResult(STATUS.SUCCESS, { result }); + return; + } catch (e) { + console.error(e) + ctx.body = ctx.service.utils.resResult(STATUS.WRONG_PARMS, { result: [] }); + return; + } + } + + public async streamToExcekData(stream: FileStream): Promise<{ serverId: number, roleId: string, rewards: string }[]> { + return new Promise((resolve, reject) => { + let exceldata = []; + stream.on('error', reject); + stream.on('data', function(chunk) { + const workbook = XLSX.read(chunk); + for(let sheet in workbook.Sheets) { + if(workbook.Sheets.hasOwnProperty(sheet)) { + exceldata = XLSX.utils.sheet_to_json(workbook.Sheets[sheet]); break; } } - if(flag) { - continue; - } else { - result = file; - dirPath += `/${file}`; - }; - } - if(!result) { - throw new Error(msg); - } - - // 历史记录压缩移动 - console.log('历史记录压缩移动'); - let isEmpty = true; - try { - let oldFiles:any = fs.readdirSync(hotUpdateAddr); - console.log(oldFiles.length); - isEmpty = oldFiles.length <= 0; - } catch(e) { - isEmpty = true; - } - if(!isEmpty) { - await compressing.zip.compressDir(hotUpdateAddr, `${dirPath}/${folderName}.zip`); - if (!fs.existsSync(publishPath)) { - fs.mkdirSync(publishPath); - } - let versionManifest: string = ''; - try { - let version = JSON.parse(fs.readFileSync(`${hotUpdateAddr}/version.manifest`)); - versionManifest = version.version; - }catch(e) { - console.log(e); - } - fs.renameSync(`${dirPath}/${folderName}.zip`, `${publishPath}/${folderName}_${versionManifest}_${moment().format('YYMMDDHHmmss')}.zip`); - - // 删除原始文件 - this.deleteFolder(hotUpdateAddr); - } - - // 保存新文件 - console.log('保存至热更新地址'); - fs.renameSync(dirPath, hotUpdateAddr); - - temp.cleanupSync(); - return ctx.body = ctx.service.utils.resResult(STATUS.SUCCESS); - - } catch (err) { - console.log(err) - return ctx.body = ctx.service.utils.resResult(STATUS.GM_UPLOAD_FORMAT_ERR, null, err.message); - } - - } else { - return ctx.body = ctx.service.utils.resResult(STATUS.GM_UPLOAD_FORMAT_ERR); - } - } - - private async doUnzipExtra(stream: Stream, dirPath: string) { - return new Promise((resolve, reject) => { - // 解压上传文件的stream - var unzipExtractor = unzip.Extract({ path: dirPath }); - unzipExtractor.on('close', function() { - resolve(null); + }); + stream.on('end', () => resolve(exceldata)) }); - - unzipExtractor.on('close', function(e) { - reject(e); - }); - - stream.pipe(unzipExtractor); // 异步写入文件 - }) - } - - private jsonFolder = '/app/resource/jsons'; - private warjsonFolder = '/app/resource/warJsons'; - private tsFolder = '/app/pubUtils'; - - private distJsonFolder = `/../game-server/dist${this.jsonFolder}`; - private distWarjsonFolder = `/../game-server/dist${this.warjsonFolder}`; - private distTsFolder = `/../game-server/dist${this.tsFolder}`; - - public async uploadJson() { - const { ctx } = this; - - - const parts = ctx.multipart({ }); - const files = []; - - try { - let stream; - let writeStream; - - while ((stream = await parts()) != null) { - console.log('******', stream); - const filename = stream.filename; - let filenameWithoutEx = filename?filename.split('.')[0]:''; - if (stream.mimeType == 'application/json') { - if (filenameWithoutEx.match(/^\d{1,}$/)) { - let target1 = path.join(this.config.baseDir, this.warjsonFolder, filename); - let target2 = path.join(this.config.baseDir, this.distWarjsonFolder, filename); - writeStream = fs.createWriteStream(target1); - await pump(stream, writeStream); - fs.copyFileSync(target1, target2); - files.push(filename); - } else { - let target1 = path.join(this.config.baseDir, this.jsonFolder, filename); - let target2 = path.join(this.config.baseDir, this.distJsonFolder, filename); - writeStream = fs.createWriteStream(target1); - await pump(stream, writeStream); - fs.copyFileSync(target1, target2); - files.push(filename); - } - } else if (stream.mimeType == 'application/octet-stream') { - let target1 = path.join(this.config.baseDir, this.tsFolder, 'dicParam.js'); - let target2 = path.join(this.config.baseDir, this.distTsFolder, filename); - writeStream = fs.createWriteStream(target1); - await pump(stream, writeStream); - fs.copyFileSync(target1, target2); - files.push(filename); - } - - let envs = decodeArrayStr(ctx.request.headers.env||'', ','); - - if(envs.length > 0) { // 转发 - for(let env of envs) { - if(env == ctx.app.config.realEnv) continue; - await ctx.service.utils.transmit(env, ctx.request.url, writeStream); - } - } - sendToWormhole(stream); - } - - }catch(e) { - console.error(e); - } - - return ctx.body = ctx.service.utils.resResult(STATUS.SUCCESS, { - "files": files - }); - - // console.log('****', stream); - // // const filename = stream.filename; - // // const target = path.join(url, filename); - - // if(stream.mimeType == 'application/zip') { - // try { - // let dirPath = await temp.mkdir(this.jsonFolderName); // 临时文件夹 - - // console.log('读取文件'); - // await this.doUnzipExtra(stream, dirPath); - // let files = new Array<{path:string,name:string}>(); - // this.getFileList(dirPath, files); - // console.log(files); - - // console.log('保存文件'); - // if (!fs.existsSync(this.jsonFolderPath)) { - // fs.mkdirSync(this.jsonFolderPath); - // } - // for (let {path, name} of files) { - // console.log(`${this.jsonFolderPath}/${name}`); - // fs.renameSync(path, `${this.jsonFolderPath}/${name}`); - // } - - // temp.cleanupSync(); - // return ctx.body = ctx.service.utils.resResult(STATUS.SUCCESS, { - // "files": JSON.stringify(files) - // }); - // } catch (err) { - // console.log(err) - // return ctx.body = ctx.service.utils.resResult(STATUS.INTERNAL_ERR); - // } - - // } else { - // return ctx.body = ctx.service.utils.resResult(STATUS.GM_UPLOAD_FORMAT_ERR); - // } - } - - public async reloadResource() { - const { ctx } = this; - - try { - - reloadResources(); - ctx.body = ctx.service.utils.resResult(STATUS.SUCCESS, { isOK: true }); - return; - } catch(e) { - ctx.body = ctx.service.utils.resResult(STATUS.SUCCESS, { isOK: false, err: e.stack }); - return; - } -} - -public async uploadQrCode() { - const { ctx } = this; - - try { - const { ctx } = this; - const parts = ctx.multipart(); - let part, env = ctx.request.headers.env, type = ctx.request.headers.type, fileName = '', writePath = '', ext = '', remoteUrl = ''; - while ((part = await parts()) != null) { - if (part.length) { - console.log('kv: ', `${part[0]}: ${part[1]}`); - } else { - if (!part.filename) continue; - - let filenames = part.filename.split('.'); - ext = filenames[filenames.length - 1]; - if(type == 'popNotice'|| type == 'loginPage' || type == 'loadingPage' || type == 'icon') { - writePath = getLocalImgUrl(this.app.config.realEnv, type); - fileName = `${moment().valueOf()}.${ext}`; - remoteUrl = getRemoteImgUrl(this.app.config.realEnv, fileName, type); - } else { - writePath = getLocalQrCodeUrl(this.app.config.realEnv, env); - fileName = `QR${moment().valueOf()}.${ext}`; - remoteUrl = getRemoteQrCodeUrl(env, fileName); - } - - let fullPath = `${writePath}/${fileName}`; - try { - fs.accessSync(writePath); - } catch (err) { - if (err) { - fs.mkdirSync(writePath, { recursive: true }); - } - } - if (!fs.existsSync(fullPath)) { - fs.writeFileSync(fullPath, ''); - } - const writeStream = fs.createWriteStream(fullPath); - await pump(part, writeStream); - - // remoteUrl = `${getRemoteRplUrl(ctx.app.config.realEnv, roleId, warType, battleCode)}/${battleCode}.bin`; - } - await sendToWormhole(part); - } - ctx.body = ctx.service.utils.resResult(STATUS.SUCCESS, { isOK: true, url: remoteUrl, ext }); - return; - } catch(e) { - ctx.body = ctx.service.utils.resResult(STATUS.SUCCESS, { isOK: false, err: e.stack }); - return; - } -} + } } export function childExec(commond: string) { return new Promise((resolve, reject) => { - exec(commond, function(error, stdout, stderr){ - if(error) { + exec(commond, function (error, stdout, stderr) { + if (error) { reject(error); return; } diff --git a/gm-server/app/router.ts b/gm-server/app/router.ts index 6d64bbac4..a0dcf8d10 100644 --- a/gm-server/app/router.ts +++ b/gm-server/app/router.ts @@ -13,6 +13,7 @@ export default (app: Application) => { router.post('/api/upload/uploadjson', tokenParser, controller.upload.uploadJson); router.post('/api/upload/reloadresource', tokenParser, controller.upload.reloadResource); router.post('/api/upload/uploadqrcode', tokenParser, controller.upload.uploadQrCode); + router.post('/api/upload/uploadmailexcel', tokenParser, controller.upload.uploadMailExcel); router.post('/api/gmaccount/getgmlist', tokenParser, controller.gmaccount.getGmList); router.post('/api/gmaccount/createaccount', tokenParser,controller.gmaccount.createGmAccount); diff --git a/gm-server/app/service/Mail.ts b/gm-server/app/service/Mail.ts index d69b99854..bc9035a29 100644 --- a/gm-server/app/service/Mail.ts +++ b/gm-server/app/service/Mail.ts @@ -23,7 +23,7 @@ export default class Mail extends Service { role = await RoleModel.findByRoleId(roleId); } if(roleName) { - role = await RoleModel.findByRoleName(roleName); + role = await RoleModel.findByRoleName(roleName, serverId); } if(!role || role.serverId != serverId) return this.ctx.service.utils.resResult(STATUS.WRONG_PARMS); return this.ctx.service.utils.resResult(STATUS.SUCCESS, { env: this.ctx.app.config.realEnv, serverId, roleId: role.roleId, roleName: role.roleName }) diff --git a/gm-server/config/config.default.ts b/gm-server/config/config.default.ts index ae3aa4cc0..b8b234861 100644 --- a/gm-server/config/config.default.ts +++ b/gm-server/config/config.default.ts @@ -47,9 +47,9 @@ export default (appInfo: EggAppInfo) => { fileSize: '100mb', mode: 'stream', whitelist: [ - '.json', '.ts', '.zip', '.jpg', '.png', '.jpeg', '.mp4', '.gif' + '.json', '.ts', '.zip', '.jpg', '.png', '.jpeg', '.mp4', '.gif', '.xls', '.xlsx' ], - fileExtensions: ['.json', '.ts', '.zip', '.jpg', '.png', '.jpeg', '.mp4', '.gif'], // 扩展几种上传的文件格式 + fileExtensions: ['.json', '.ts', '.zip', '.jpg', '.png', '.jpeg', '.mp4', '.gif', '.xls', '.xlsx'], // 扩展几种上传的文件格式 autoFields: true }; diff --git a/gm-server/package.json b/gm-server/package.json index 62ec2903b..e392975cc 100644 --- a/gm-server/package.json +++ b/gm-server/package.json @@ -36,10 +36,12 @@ "egg-cors": "^2.2.3", "egg-http-proxy-middleware": "^1.0.3", "egg-scripts": "^2.6.0", + "egg-xtransit": "^2.0.0", "exceljs": "^4.3.0", "form-data": "^4.0.0", "formstream": "^1.1.1", "moment": "^2.29.0", + "node-xlsx": "^0.23.0", "pump": "^3.0.0", "reflect-metadata": "^0.1.13", "stream-wormhole": "^1.1.0", @@ -53,12 +55,12 @@ "@types/supertest": "^2.0.0", "autod": "^3.0.1", "autod-egg": "^1.1.0", - "egg-ci": "^1.8.0", "egg-bin": "^4.11.0", + "egg-ci": "^1.8.0", "egg-mock": "^3.16.0", - "tslib": "^1.9.0", "eslint": "^6.7.2", "eslint-config-egg": "^8.0.0", + "tslib": "^1.9.0", "typescript": "^3.0.0" }, "engines": { diff --git a/shared/db/GMMail.ts b/shared/db/GMMail.ts index e07166e82..06857780c 100644 --- a/shared/db/GMMail.ts +++ b/shared/db/GMMail.ts @@ -10,7 +10,7 @@ import { GMMail as StategyMail } from './ServerStategy'; import { ServerlistType } from './Serverlist'; import moment = require('moment'); -class Reward { +class MailReward { @prop({ required: true }) id: number; @prop({ required: true }) @@ -26,6 +26,8 @@ export class Receiver { roleId?: string; @prop({ required: true }) roleName?: string; + @prop({ required: true, type: MailReward, _id: false }) + rewards?: MailReward[]; } export default class GMMail extends BaseModel { @@ -33,8 +35,8 @@ export default class GMMail extends BaseModel { @prop({ required: false}) hasGoods: boolean; // 有效时间,单位小时 - @prop({ required: true, type: Reward, default: [], _id: false }) - goods: Reward[]; + @prop({ required: true, type: MailReward, default: [], _id: false }) + goods: MailReward[]; @prop({ required: true, default: true }) timeType: MAIL_TIME_TYPE; // 邮件时间类型 diff --git a/shared/db/Role.ts b/shared/db/Role.ts index c0800fd7d..bd613ba70 100644 --- a/shared/db/Role.ts +++ b/shared/db/Role.ts @@ -404,8 +404,8 @@ export default class Role extends BaseModel { return role; } - public static async findByRoleName(roleName: string, select?: string, getters = false, virtuals = true) { - const role: RoleType = await RoleModel.findOne({ roleName }).select(select).lean({ getters, virtuals }); + public static async findByRoleName(roleName: string, serverId: number, select?: string, getters = false, virtuals = true) { + const role: RoleType = await RoleModel.findOne({ roleName, serverId }).select(select).lean({ getters, virtuals }); return role; } diff --git a/shared/domain/backEndField/params.ts b/shared/domain/backEndField/params.ts index 9fbba1b6f..71c4a3128 100644 --- a/shared/domain/backEndField/params.ts +++ b/shared/domain/backEndField/params.ts @@ -20,14 +20,14 @@ export class UpdateMailParams { content: string; sendName: string; mailType: GM_MAIL_TYPE; // 收件人类型 - receivers: {env: string; serverId: number; roleId: string; roleName: string; }[]; + receivers: {env: string; serverId: number; roleId: string; roleName: string; rewards: {id: number; count: number}[] }[]; reason: string; // 原因 isSp: boolean = false; // 特殊邮件 isSingle: boolean; constructor(obj: UpdateMailParams) { this.goods = obj.goods; - this.hasGoods = obj.goods?.length > 0; + if(obj.goods && obj.goods?.length > 0) this.hasGoods = true; this.timeType = obj.timeType; this.expire = obj.expire; this.startTime = obj.startTime; @@ -44,6 +44,12 @@ export class UpdateMailParams { this.mailType = GM_MAIL_TYPE.SERVER; } this.receivers = obj.receivers; + if(obj.receivers && obj.receivers.length > 0) { + for(let { rewards } of obj.receivers) { + console.log('#### rewards', rewards) + if(rewards && rewards.length > 0) this.hasGoods = true; + } + } this.reason = obj.reason; this.isSp = obj.isSp; } diff --git a/shared/resource/jsons/dic_api.json b/shared/resource/jsons/dic_api.json index 1e96776d5..a0309feb8 100644 --- a/shared/resource/jsons/dic_api.json +++ b/shared/resource/jsons/dic_api.json @@ -999,5 +999,12 @@ "name": "上传二维码", "module": "server", "type": "update" + }, + { + "id": 144, + "api": "/api/upload/uploadmailexcel", + "name": "上传excel", + "module": "server", + "type": "update" } ] \ No newline at end of file