123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- import { ApiResponse, ApiTags, ApiQuery } from '@midwayjs/swagger';
- import { Validate } from '@midwayjs/validate';
- import { Controller, Inject, Get, Param, Post, Body, Del, Query, Config } from '@midwayjs/core';
- import { cloneDeep, get, head, isArray, omit, pick } from 'lodash';
- import { ServiceError, ErrorCode } from '../../error/service.error';
- import { BaseController } from '../../frame/BaseController';
- import { MatchRegistrationService } from '../../service/match/matchRegistration.service';
- import { UserService } from '../../service/system/user.service';
- import * as bcrypt from 'bcryptjs';
- import * as Path from 'path'
- import dayjs = require('dayjs');
- import { MatchService } from '../../service/platform/match.service';
- import { ServiceUtilService } from '../../service/serviceUtil.service';
- import * as Excel from 'exceljs';
- import { UtilService } from '../../service/util.service';
- import { AliyunSmsService } from '../../service/thirdParty/aliyunSms.service';
- const namePrefix = '创新大赛-赛事报名';
- @ApiTags(['创新大赛-赛事报名'])
- @Controller('/matchReg', { tagName: namePrefix })
- export class MatchRegistrationController implements BaseController {
- @Inject()
- service: MatchRegistrationService;
- @Inject()
- userService: UserService;
- @Inject()
- matchService: MatchService
- @Inject()
- serviceUtil: ServiceUtilService
- @Inject()
- utilService: UtilService;
- @Inject()
- smsService: AliyunSmsService
- @Config('PathConfig.path')
- path;
- @Get('/')
- @ApiTags('列表查询')
- @ApiQuery({ name: 'query' })
- async index(@Query() query: object) {
- const qobj = omit(query, ['skip', 'limit']);
- const others: any = pick(query, ['skip', 'limit']);
- others.order = { time: 'ASC' };
- const { data, total } = await this.service.query(qobj, others);
- const fillList = []
- for (const i of data) {
- let newItem = cloneDeep(i)
- const user_id = get(i, 'user_id')
- const user = await this.userService.fetch({ id: user_id })
- if (user) newItem.user_name = get(user, 'nick_name')
- const match_id = get(i, 'match_id')
- const match = await this.matchService.fetch({ id: match_id })
- if (match) newItem.match_name = get(match, 'name')
- fillList.push(newItem)
- }
- return { data: fillList, total };
- }
- @Get('/:id')
- @ApiTags('单查询')
- async fetch(@Param('id') id: number) {
- const data = await this.service.fetch({ id });
- return data;
- }
- @Post('/', { routerName: `创建${namePrefix}` })
- @ApiTags('创建数据')
- @Validate()
- async create(@Body() data: object) {
- const userColumns = ['user', 'user_id'];
- let regData = omit(data, userColumns);
- let returnUser = {};
- if (get(data, 'user_id')) {
- regData = { user_id: get(data, 'user_id'), ...regData };
- } else {
- const user = get(data, 'user');
- if (!user) throw new ServiceError(ErrorCode.MATCH_NEED_USER_INFO);
- // 注册用户
- await this.userService.createExamine(user);
- await this.userService.checkPhone(user);
- await this.userService.checkEmail(user);
- // 处理密码, TODO:可能会要自动生成
- const password = get(user, 'password');
- if (password) {
- const salt = bcrypt.genSaltSync(10);
- const hash = bcrypt.hashSync(password, salt);
- Object.assign(user, { password: hash });
- }
- returnUser = { password, account: get(user, 'account') }
- // 发送短信
- try {
- const phone = get(user, 'phone')
- const msg = { "账号": get(user, 'account'), "密码": password }
- await this.smsService.send(phone, msg)
- } catch (error) {
- console.error('matchReg - create:发送短信发生错误')
- }
- const dbData = await this.userService.create(user);
- regData = { user_id: dbData.id, ...regData };
- }
- // 检查是否报名
- const query = { match_id: get(data, 'match_id'), user_id: get(regData, 'user_id') };
- const { total } = await this.service.query(query);
- if (total > 0) throw new ServiceError(ErrorCode.MATCH_USER_HAS_REGISTED);
- // 制作项目编号
- const { total: matchRegTotal = 0 } = await this.service.query({ match_id: get(data, 'match_id') });
- const no = `${get(data, 'match_id')}-${get(regData, 'user_id')}-${matchRegTotal + 1}`;
- regData = { ...regData, no, time: dayjs().format('YYYY-MM-DD HH:mm:ss') };
- const result = await this.service.create(regData);
- if (Object.keys(returnUser).length > 0) return returnUser
- else return result;
- }
- @Post('/:id', { routerName: `修改${namePrefix}` })
- @ApiTags('修改数据')
- @Validate()
- async update(@Param('id') id: number, @Body() data: object) {
- if (!id) throw new ServiceError(ErrorCode.ID_NOT_FOUND);
- const result = await this.service.update({ id }, data);
- if (get(result, 'stauts') === '-1') {
- //被退回,发送短信
- const user_id = get(result, 'user_id')
- const user = await this.userService.fetch({ id: user_id })
- if (!user) throw new ServiceError(ErrorCode.USER_NOT_FOUND)
- const match_id = get(result, 'match_id')
- const match = await this.matchService.fetch({ id: match_id })
- if (!match) throw new ServiceError(ErrorCode.MATCH_NOT_FOUND)
- const match_name = get(match, 'match_name')
- const phone = get(user, 'phone')
- const msg = `您提交的的 ${match_name} 赛事申请已被退回,请登录平台进行修改后提交`
- try {
- await this.smsService.send(phone, msg)
- } catch (error) {
- console.error('matchReg - update:发送短信发生错误')
- }
- }
- return result;
- }
- @Del('/:id', { routerName: `删除${namePrefix}` })
- @ApiTags('删除数据')
- @Validate()
- async delete(@Param('id') id: number) {
- if (!id) throw new ServiceError(ErrorCode.ID_NOT_FOUND);
- const result = await this.service.delete({ id });
- return result;
- }
- @Get('/detail/:id')
- async detail(@Param('id') id: string) {
- const data = await this.service.fetch({ id });
- return data;
- }
- @Get('/view/:match_id', { routerName: '查看初赛名单结果' })
- async viewOrderByScore(@Param('match_id') match_id: string) {
- const query = { match_id, status: '0' }
- const others = { order: { score: 'DESC' } }
- const { data: list } = await this.service.query(query, others)
- const match = await this.matchService.fetch({ id: match_id })
- const match_name = get(match, 'name')
- for (const i of list) {
- const user_id = get(i, 'user_id')
- const user = await this.userService.fetch({ id: user_id })
- if (user) i.user_name = get(user, 'nick_name')
- if (match_name) i.match_name = match_name
- delete i.info;
- }
- return list
- }
- @Get('/export/:match_id', { routerName: `导出初赛名单` })
- @ApiTags('导出初赛名单')
- async exportList(@Param('match_id') match_id: string) {
- // 查询所有未被退回的报名信息
- const { data } = await this.service.query({ match_id, status: '0' })
- // 没有人,提示该赛事没有报名人员,无法导出
- if (data.length <= 0) throw new ServiceError(ErrorCode.MATCH_NO_PERSON_TO_EXPORT)
- const match = await this.matchService.fetch({ id: match_id })
- // 没有找到赛事信息
- if (!match) throw new ServiceError(ErrorCode.MATCH_NOT_FOUND)
- // 获取赛事名称, 赛事名称放首行
- const match_name = get(match, 'name')
- const fir = ['赛事名称', match_name]
- // 第二行是表头: 项目编号,用户名称,报名时间, ...报名信息,分数
- const sec = ['项目编号', '用户名称', '报名时间']
- // 将报名信息的问题塞进来, 并整理出文件列,计算出文件列的字母
- const firstData = head(data);
- const info = get(firstData, 'info', [])
- const fileColumns = []
- for (const i of info) {
- const problem = get(i, 'problem')
- sec.push(problem)
- const type = get(i, 'type')
- if (type === '5' || type === '7') {
- const length = sec.length
- const col = this.utilService.ToExcelColumn(length - 1)
- const sid = get(i, 'sid')
- fileColumns.push({ sid, col })
- }
- }
- // 填充分数列
- sec.push('分数')
- const workbook = new Excel.Workbook();
- const sheet = workbook.addWorksheet('sheet1');
- sheet.addRow(fir)
- sheet.addRow(sec);
- // 整理数据
- for (let index = 0; index < data.length; index++) {
- const i = data[index];
- const item = [];
- // 项目编号
- const no = get(i, 'no', "")
- item.push(no)
- // 用户信息
- const user = await this.userService.fetch({ id: get(i, 'user_id') });
- if (user) item.push(get(user, 'nick_name'))
- else item.push("")
- // 报名时间
- const time = get(i, 'time', "")
- item.push(time)
- // 处理报名信息
- const info = get(i, 'info', [])
- for (const is of info) {
- const type = get(is, 'type')
- const val = get(is, 'reply', '')
- // 0:单选;2:下拉;3:单行文本;4:多行文本
- if (type === '0' || type === '2' || type === '3' || type === '4') {
- item.push(val)
- } else if (type === '1') {
- // 1:多选
- item.push(val.join(';'))
- } else if (type === '5' || type === '7') {
- // 5:图片/文件;7:附件模板
- // 1.需要确定单元格位置,生成超链接格式,1个单元格只能有一个超链接
- const sid = get(is, 'sid')
- const headFile = head(val)
- const link = {
- text: get(headFile, 'name'),
- hyperlink: get(headFile, 'uri'),
- toolTip: get(headFile, 'uri'),
- }
- const posObj = fileColumns.find(f => f.sid === sid)
- if (!posObj) continue;
- posObj.value = link;
- posObj.line = index + 1 + 2; // +1 是索引加1为行数; +2 是表格从第三行开始的
- // for (const valI of val) {
- // const fileName = get(valI, 'name')
- // // TODO:需要加上域名
- // const uri = get(valI, 'uri')
- // const link = {
- // text: fileName,
- // hyperlink: uri,
- // tooltip: uri
- // }
- // }
- } else if (type === '6') {
- // 6:数组,将sid外的 key,value拼成字符串作为内容
- if (!isArray(val)) continue;
- const midArr = []
- for (const valI of val) {
- const obj = omit(valI, ['sid'])
- for (const key in obj) {
- midArr.push(`${key}: ${obj[key]}`)
- }
- }
- // 将键值对拼成字符串
- item.push(midArr.join(';'))
- }
- }
- sheet.addRow(item)
- }
- // 处理超链接
- for (const i of fileColumns) {
- const col = get(i, 'col')
- const line = get(i, 'line')
- const pos = `${col}${line}`
- const value = get(i, 'value')
- if (!value) continue;
- sheet.getCell(pos).value = value
- }
- const nowDate = new Date().getTime();
- const filename = `${match_name}初赛名单-${nowDate}.xlsx`
- const path = this.path;
- if (!path) {
- throw new ServiceError('服务端没有设置存储路径');
- }
- const filepath = Path.resolve(path, filename);
- await workbook.xlsx.writeFile(filepath);
- return `/files/cxyy/export/${filename}`;
- }
- }
|