[Feature] 新增暂停功能以及多表字段升级 (#434)
* feat:新增暂停功能 (#416) * feat:新增暂停功能 * feat: 修改状态相关功能 (#433) Co-authored-by: luchunhui <luchunhui@didiglobal.com> * fix: 修改刷数据逻辑错误和环境变量问题 * fix: 解决lint问题 --------- Co-authored-by: chaorenluo <1243357953@qq.com> Co-authored-by: luchunhui <luchunhui@didiglobal.com>
This commit is contained in:
parent
054095e499
commit
351f18f255
22
DATA_COLLECTION.md
Normal file
22
DATA_COLLECTION.md
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# Important Disclosure re:XIAOJUSURVEY Data Collection
|
||||||
|
|
||||||
|
XIAOJUSURVEY is open-source software developed and maintained by XIAOJUSURVEY Team and available at https://github.com/didi/xiaoju-survey.
|
||||||
|
We hereby state the purpose and reason for collecting data.
|
||||||
|
|
||||||
|
## Purpose of data collection
|
||||||
|
|
||||||
|
Data collected is used to help improve XIAOJUSURVEY for all users. It is important that our team understands the usage patterns as soon as possible, so we can best decide how to design future features and prioritize current work.
|
||||||
|
|
||||||
|
## Types of data collected
|
||||||
|
|
||||||
|
XIAOJUSURVEY just collects data about version's information. The data collected is subsequently reported to the XIAOJUSURVEY's backend services.
|
||||||
|
|
||||||
|
All data collected will be used exclusively by the XIAOJUSURVEY team for analytical purposes only. The data will be neither accessible nor sold to any third party.
|
||||||
|
|
||||||
|
## Sensitive data
|
||||||
|
|
||||||
|
XIAOJUSURVEY will never collect and/or report sensitive information, such as private keys, API keys, or passwords.
|
||||||
|
|
||||||
|
## How do I opt-in to or opt-out of data sharing?
|
||||||
|
|
||||||
|
See [docs](https://xiaojusurvey.didi.cn/docs/next/community/%E6%95%B0%E6%8D%AE%E4%B8%8A%E6%8A%A5%E5%A3%B0%E6%98%8E) for information on configuring this functionality.
|
@ -169,4 +169,4 @@ _任何问题和合作可以联系小助手。_
|
|||||||
|
|
||||||
## CHANGELOG
|
## CHANGELOG
|
||||||
|
|
||||||
关注重大项目变更:[MAJOR CHANGELOG](https://github.com/didi/xiaoju-survey/issues/48)。
|
关注重大项目变更:[MAJOR CHANGELOG](https://github.com/didi/xiaoju-survey/issues/48)。
|
@ -15,7 +15,7 @@ services:
|
|||||||
- xiaoju-survey
|
- xiaoju-survey
|
||||||
|
|
||||||
xiaoju-survey:
|
xiaoju-survey:
|
||||||
image: "xiaojusurvey/xiaoju-survey:1.1.6-slim" # 最新版本:https://hub.docker.com/r/xiaojusurvey/xiaoju-survey/tags
|
image: "xiaojusurvey/xiaoju-survey:1.2.0-slim" # 最新版本:https://hub.docker.com/r/xiaojusurvey/xiaoju-survey/tags
|
||||||
container_name: xiaoju-survey
|
container_name: xiaoju-survey
|
||||||
restart: always
|
restart: always
|
||||||
ports:
|
ports:
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
XIAOJU_SURVEY_MONGO_DB_NAME=xiaojuSurvey
|
XIAOJU_SURVEY_MONGO_DB_NAME=xiaojuSurvey
|
||||||
XIAOJU_SURVEY_MONGO_URL=mongodb://127.0.0.1:27017
|
XIAOJU_SURVEY_MONGO_URL=
|
||||||
XIAOJU_SURVEY_MONGO_AUTH_SOURCE=admin
|
XIAOJU_SURVEY_MONGO_AUTH_SOURCE=admin
|
||||||
|
|
||||||
XIAOJU_SURVEY_REDIS_HOST=
|
XIAOJU_SURVEY_REDIS_HOST=
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
XIAOJU_SURVEY_MONGO_DB_NAME=xiaojuSurvey
|
||||||
|
XIAOJU_SURVEY_MONGO_URL=mongodb://127.0.0.1:27017
|
||||||
|
XIAOJU_SURVEY_MONGO_AUTH_SOURCE=admin
|
||||||
|
|
||||||
|
XIAOJU_SURVEY_REDIS_HOST=
|
||||||
|
XIAOJU_SURVEY_REDIS_PORT=
|
||||||
|
XIAOJU_SURVEY_REDIS_USERNAME=
|
||||||
|
XIAOJU_SURVEY_REDIS_PASSWORD=
|
||||||
|
XIAOJU_SURVEY_REDIS_DB=
|
||||||
|
|
||||||
|
|
||||||
|
XIAOJU_SURVEY_RESPONSE_AES_ENCRYPT_SECRET_KEY=dataAesEncryptSecretKey
|
||||||
|
XIAOJU_SURVEY_HTTP_DATA_ENCRYPT_TYPE=rsa
|
||||||
|
|
||||||
|
XIAOJU_SURVEY_JWT_SECRET=xiaojuSurveyJwtSecret
|
||||||
|
XIAOJU_SURVEY_JWT_EXPIRES_IN=8h
|
||||||
|
|
||||||
|
XIAOJU_SURVEY_LOGGER_FILENAME=./logs/app.log
|
||||||
|
|
||||||
|
XIAOJU_SURVEY_REPORT=true
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "server",
|
"name": "xiaoju-survey-server",
|
||||||
"version": "0.0.1",
|
"version": "1.3.0",
|
||||||
"description": "",
|
"description": "XIAOJUSURVEY的server端",
|
||||||
"author": "",
|
"author": "",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "nest build",
|
"build": "nest build",
|
||||||
@ -22,6 +22,7 @@
|
|||||||
"@nestjs/common": "^10.0.0",
|
"@nestjs/common": "^10.0.0",
|
||||||
"@nestjs/config": "^3.1.1",
|
"@nestjs/config": "^3.1.1",
|
||||||
"@nestjs/core": "^10.0.0",
|
"@nestjs/core": "^10.0.0",
|
||||||
|
"@nestjs/microservices": "^10.4.4",
|
||||||
"@nestjs/platform-express": "^10.0.0",
|
"@nestjs/platform-express": "^10.0.0",
|
||||||
"@nestjs/serve-static": "^4.0.0",
|
"@nestjs/serve-static": "^4.0.0",
|
||||||
"@nestjs/swagger": "^7.3.0",
|
"@nestjs/swagger": "^7.3.0",
|
||||||
@ -75,7 +76,7 @@
|
|||||||
"prettier": "^3.0.0",
|
"prettier": "^3.0.0",
|
||||||
"redis-memory-server": "^0.11.0",
|
"redis-memory-server": "^0.11.0",
|
||||||
"source-map-support": "^0.5.21",
|
"source-map-support": "^0.5.21",
|
||||||
"supertest": "^6.3.3",
|
"supertest": "^7.0.0",
|
||||||
"ts-jest": "^29.1.0",
|
"ts-jest": "^29.1.0",
|
||||||
"ts-loader": "^9.4.3",
|
"ts-loader": "^9.4.3",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
|
62
server/scripts/run-report.ts
Normal file
62
server/scripts/run-report.ts
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
import fs, { promises as fsa } from 'fs-extra';
|
||||||
|
import path from 'path';
|
||||||
|
import fetch from 'node-fetch';
|
||||||
|
|
||||||
|
interface PackageJson {
|
||||||
|
type?: string;
|
||||||
|
name?: string;
|
||||||
|
version?: string;
|
||||||
|
description?: string;
|
||||||
|
id?: string;
|
||||||
|
msg?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const getId = () => {
|
||||||
|
const id = new Date().getTime().toString();
|
||||||
|
process.env.XIAOJU_SURVEY_REPORT_ID = id;
|
||||||
|
|
||||||
|
return id;
|
||||||
|
};
|
||||||
|
|
||||||
|
const readData = async (directory: string): Promise<PackageJson | null> => {
|
||||||
|
const packageJsonPath = path.join(directory, 'package.json');
|
||||||
|
const id = process.env.XIAOJU_SURVEY_REPORT_ID || getId();
|
||||||
|
try {
|
||||||
|
if (!fs.existsSync(directory)) {
|
||||||
|
return {
|
||||||
|
type: 'server',
|
||||||
|
name: '',
|
||||||
|
version: '',
|
||||||
|
description: '',
|
||||||
|
id,
|
||||||
|
msg: '文件不存在',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const data = await fsa.readFile(packageJsonPath, 'utf8').catch((e) => e);
|
||||||
|
const { name, version, description } = JSON.parse(data) as PackageJson;
|
||||||
|
return { type: 'server', name, version, description, id };
|
||||||
|
} catch (error) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
(async (): Promise<void> => {
|
||||||
|
if (
|
||||||
|
process.env.NODE_ENV === 'development' &&
|
||||||
|
!process.env.XIAOJU_SURVEY_REPORT
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await readData(path.join(process.cwd()));
|
||||||
|
|
||||||
|
// 上报
|
||||||
|
fetch('https://xiaojusurveysrc.didi.cn/reportSourceData', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
Accept: 'application/json, */*',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify(res),
|
||||||
|
}).catch(() => {});
|
||||||
|
})();
|
@ -14,6 +14,7 @@ import { AuthModule } from './modules/auth/auth.module';
|
|||||||
import { MessageModule } from './modules/message/message.module';
|
import { MessageModule } from './modules/message/message.module';
|
||||||
import { FileModule } from './modules/file/file.module';
|
import { FileModule } from './modules/file/file.module';
|
||||||
import { WorkspaceModule } from './modules/workspace/workspace.module';
|
import { WorkspaceModule } from './modules/workspace/workspace.module';
|
||||||
|
import { UpgradeModule } from './modules/upgrade/upgrade.module';
|
||||||
|
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
|
|
||||||
@ -35,18 +36,21 @@ import { MessagePushingLog } from './models/messagePushingLog.entity';
|
|||||||
import { WorkspaceMember } from './models/workspaceMember.entity';
|
import { WorkspaceMember } from './models/workspaceMember.entity';
|
||||||
import { Workspace } from './models/workspace.entity';
|
import { Workspace } from './models/workspace.entity';
|
||||||
import { Collaborator } from './models/collaborator.entity';
|
import { Collaborator } from './models/collaborator.entity';
|
||||||
|
import { DownloadTask } from './models/downloadTask.entity';
|
||||||
|
import { Session } from './models/session.entity';
|
||||||
|
|
||||||
import { LoggerProvider } from './logger/logger.provider';
|
import { LoggerProvider } from './logger/logger.provider';
|
||||||
import { PluginManagerProvider } from './securityPlugin/pluginManager.provider';
|
import { PluginManagerProvider } from './securityPlugin/pluginManager.provider';
|
||||||
import { LogRequestMiddleware } from './middlewares/logRequest.middleware';
|
import { LogRequestMiddleware } from './middlewares/logRequest.middleware';
|
||||||
import { PluginManager } from './securityPlugin/pluginManager';
|
import { PluginManager } from './securityPlugin/pluginManager';
|
||||||
import { Logger } from './logger';
|
import { Logger } from './logger';
|
||||||
import { DownloadTask } from './models/downloadTask.entity';
|
|
||||||
import { Session } from './models/session.entity';
|
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
ConfigModule.forRoot({}),
|
ConfigModule.forRoot({
|
||||||
|
envFilePath: `.env.${process.env.NODE_ENV}`, // 根据 NODE_ENV 动态加载对应的 .env 文件
|
||||||
|
isGlobal: true, // 使配置模块在应用的任何地方可用
|
||||||
|
}),
|
||||||
TypeOrmModule.forRootAsync({
|
TypeOrmModule.forRootAsync({
|
||||||
imports: [ConfigModule],
|
imports: [ConfigModule],
|
||||||
inject: [ConfigService],
|
inject: [ConfigService],
|
||||||
@ -104,6 +108,7 @@ import { Session } from './models/session.entity';
|
|||||||
MessageModule,
|
MessageModule,
|
||||||
FileModule,
|
FileModule,
|
||||||
WorkspaceModule,
|
WorkspaceModule,
|
||||||
|
UpgradeModule,
|
||||||
],
|
],
|
||||||
controllers: [AppController],
|
controllers: [AppController],
|
||||||
providers: [
|
providers: [
|
||||||
|
6
server/src/enums/downloadTaskStatus.ts
Normal file
6
server/src/enums/downloadTaskStatus.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export enum DOWNLOAD_TASK_STATUS {
|
||||||
|
WAITING = 'waiting', // 排队中
|
||||||
|
COMPUTING = 'computing', // 计算中
|
||||||
|
SUCCEED = 'succeed', // 导出成功
|
||||||
|
FAILED = 'failed', // 导出失败
|
||||||
|
}
|
@ -21,6 +21,7 @@ export enum EXCEPTION_CODE {
|
|||||||
RESPONSE_OVER_LIMIT = 9003, // 超出限制
|
RESPONSE_OVER_LIMIT = 9003, // 超出限制
|
||||||
RESPONSE_SCHEMA_REMOVED = 9004, // 问卷已删除
|
RESPONSE_SCHEMA_REMOVED = 9004, // 问卷已删除
|
||||||
RESPONSE_DATA_DECRYPT_ERROR = 9005, // 问卷已删除
|
RESPONSE_DATA_DECRYPT_ERROR = 9005, // 问卷已删除
|
||||||
|
RESPONSE_PAUSING = 9006, // 问卷已暂停
|
||||||
|
|
||||||
UPLOAD_FILE_ERROR = 5001, // 上传文件错误
|
UPLOAD_FILE_ERROR = 5001, // 上传文件错误
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
// 状态类型
|
// 状态类型
|
||||||
export enum RECORD_STATUS {
|
export enum RECORD_STATUS {
|
||||||
NEW = 'new', // 新建
|
NEW = 'new', // 新建 | 未发布
|
||||||
EDITING = 'editing', // 编辑
|
|
||||||
PAUSING = 'pausing', // 暂停
|
|
||||||
PUBLISHED = 'published', // 发布
|
PUBLISHED = 'published', // 发布
|
||||||
REMOVED = 'removed', // 删除
|
EDITING = 'editing', // 编辑
|
||||||
FORCE_REMOVED = 'forceRemoved', // 从回收站删除
|
FINISHED = 'finished', // 已结束
|
||||||
COMPUTING = 'computing', // 计算中
|
REMOVED = 'removed',
|
||||||
FINISHED = 'finished', // 已完成
|
}
|
||||||
ERROR = 'error', // 错误
|
|
||||||
|
export const enum RECORD_SUB_STATUS {
|
||||||
|
DEFAULT = '', // 默认
|
||||||
|
PAUSING = 'pausing', // 暂停
|
||||||
}
|
}
|
||||||
|
|
||||||
// 历史类型
|
// 历史类型
|
||||||
|
4
server/src/enums/surveySessionStatus.ts
Normal file
4
server/src/enums/surveySessionStatus.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export enum SESSION_STATUS {
|
||||||
|
ACTIVATED = 'activated',
|
||||||
|
DEACTIVATED = 'deactivated',
|
||||||
|
}
|
@ -24,6 +24,7 @@ export class SessionGuard implements CanActivate {
|
|||||||
}
|
}
|
||||||
const sessionInfo = await this.sessionService.findOne(sessionId);
|
const sessionInfo = await this.sessionService.findOne(sessionId);
|
||||||
request.sessionInfo = sessionInfo;
|
request.sessionInfo = sessionInfo;
|
||||||
|
request.surveyId = sessionInfo.surveyId;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -119,7 +119,7 @@ export enum MemberType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface BaseConf {
|
export interface BaseConf {
|
||||||
begTime: string;
|
beginTime: string;
|
||||||
endTime: string;
|
endTime: string;
|
||||||
answerBegTime: string;
|
answerBegTime: string;
|
||||||
answerEndTime: string;
|
answerEndTime: string;
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
import * as log4js from 'log4js';
|
import * as log4js from 'log4js';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { Injectable, Scope } from '@nestjs/common';
|
import { Injectable, Scope, Inject } from '@nestjs/common';
|
||||||
|
import { CONTEXT, RequestContext } from '@nestjs/microservices';
|
||||||
|
|
||||||
const log4jsLogger = log4js.getLogger();
|
const log4jsLogger = log4js.getLogger();
|
||||||
|
|
||||||
@Injectable({ scope: Scope.REQUEST })
|
@Injectable({ scope: Scope.REQUEST })
|
||||||
export class Logger {
|
export class Logger {
|
||||||
private static inited = false;
|
private static inited = false;
|
||||||
private traceId: string;
|
|
||||||
|
constructor(@Inject(CONTEXT) private readonly ctx: RequestContext) {}
|
||||||
|
|
||||||
static init(config: { filename: string }) {
|
static init(config: { filename: string }) {
|
||||||
if (Logger.inited) {
|
if (Logger.inited) {
|
||||||
@ -37,16 +40,14 @@ export class Logger {
|
|||||||
const datetime = moment().format('YYYY-MM-DD HH:mm:ss.SSS');
|
const datetime = moment().format('YYYY-MM-DD HH:mm:ss.SSS');
|
||||||
const level = options?.level;
|
const level = options?.level;
|
||||||
const dltag = options?.dltag ? `${options.dltag}||` : '';
|
const dltag = options?.dltag ? `${options.dltag}||` : '';
|
||||||
const traceIdStr = this.traceId ? `traceid=${this.traceId}||` : '';
|
const traceIdStr = this.ctx?.['traceId']
|
||||||
|
? `traceid=${this.ctx?.['traceId']}||`
|
||||||
|
: '';
|
||||||
return log4jsLogger[level](
|
return log4jsLogger[level](
|
||||||
`[${datetime}][${level.toUpperCase()}]${dltag}${traceIdStr}${message}`,
|
`[${datetime}][${level.toUpperCase()}]${dltag}${traceIdStr}${message}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
setTraceId(traceId: string) {
|
|
||||||
this.traceId = traceId;
|
|
||||||
}
|
|
||||||
|
|
||||||
info(message, options?: { dltag?: string }) {
|
info(message, options?: { dltag?: string }) {
|
||||||
return this._log(message, { ...options, level: 'info' });
|
return this._log(message, { ...options, level: 'info' });
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,9 @@ export const genTraceId = ({ ip }) => {
|
|||||||
} else {
|
} else {
|
||||||
ipArr = ip
|
ipArr = ip
|
||||||
.split('.')
|
.split('.')
|
||||||
.map((item) => parseInt(item).toString(16).padStart(2, '0'));
|
.map((item) =>
|
||||||
|
item ? parseInt(item).toString(16).padStart(2, '0') : '',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return `${ipArr.join('')}${Date.now().toString()}${getCountStr()}${process.pid.toString().slice(-5)}`;
|
return `${ipArr.join('')}${Date.now().toString()}${getCountStr()}${process.pid.toString().slice(-5)}`;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { NestFactory } from '@nestjs/core';
|
import { NestFactory } from '@nestjs/core';
|
||||||
import { AppModule } from './app.module';
|
import { AppModule } from './app.module';
|
||||||
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
|
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
|
||||||
|
import 'scripts/run-report';
|
||||||
|
|
||||||
async function bootstrap() {
|
async function bootstrap() {
|
||||||
const PORT = process.env.PORT || 3000;
|
const PORT = process.env.PORT || 3000;
|
||||||
|
@ -12,7 +12,7 @@ export class LogRequestMiddleware implements NestMiddleware {
|
|||||||
const userAgent = req.get('user-agent') || '';
|
const userAgent = req.get('user-agent') || '';
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
const traceId = genTraceId({ ip });
|
const traceId = genTraceId({ ip });
|
||||||
this.logger.setTraceId(traceId);
|
req['traceId'] = traceId;
|
||||||
const query = JSON.stringify(req.query);
|
const query = JSON.stringify(req.query);
|
||||||
const body = JSON.stringify(req.body);
|
const body = JSON.stringify(req.body);
|
||||||
this.logger.info(
|
this.logger.info(
|
||||||
|
@ -1,43 +1,13 @@
|
|||||||
import { Column, ObjectIdColumn, BeforeInsert, BeforeUpdate } from 'typeorm';
|
import { ObjectIdColumn, CreateDateColumn, UpdateDateColumn } from 'typeorm';
|
||||||
import { ObjectId } from 'mongodb';
|
import { ObjectId } from 'mongodb';
|
||||||
import { RECORD_STATUS } from '../enums';
|
|
||||||
|
|
||||||
export class BaseEntity {
|
export class BaseEntity {
|
||||||
@ObjectIdColumn()
|
@ObjectIdColumn()
|
||||||
_id: ObjectId;
|
_id: ObjectId;
|
||||||
|
|
||||||
@Column()
|
@CreateDateColumn({ type: 'timestamp', precision: 3 })
|
||||||
curStatus: {
|
createdAt: Date;
|
||||||
status: RECORD_STATUS;
|
|
||||||
date: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
@Column()
|
@UpdateDateColumn({ type: 'timestamp', precision: 3 })
|
||||||
statusList: Array<{
|
updatedAt: Date;
|
||||||
status: RECORD_STATUS;
|
|
||||||
date: number;
|
|
||||||
}>;
|
|
||||||
|
|
||||||
@Column()
|
|
||||||
createDate: number;
|
|
||||||
|
|
||||||
@Column()
|
|
||||||
updateDate: number;
|
|
||||||
|
|
||||||
@BeforeInsert()
|
|
||||||
initDefaultInfo() {
|
|
||||||
const now = Date.now();
|
|
||||||
if (!this.curStatus) {
|
|
||||||
const curStatus = { status: RECORD_STATUS.NEW, date: now };
|
|
||||||
this.curStatus = curStatus;
|
|
||||||
this.statusList = [curStatus];
|
|
||||||
}
|
|
||||||
this.createDate = now;
|
|
||||||
this.updateDate = now;
|
|
||||||
}
|
|
||||||
|
|
||||||
@BeforeUpdate()
|
|
||||||
onUpdate() {
|
|
||||||
this.updateDate = Date.now();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -11,4 +11,16 @@ export class Collaborator extends BaseEntity {
|
|||||||
|
|
||||||
@Column('jsonb')
|
@Column('jsonb')
|
||||||
permissions: Array<string>;
|
permissions: Array<string>;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
creator: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
creatorId: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
operator: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
operatorId: string;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { Entity, Column } from 'typeorm';
|
import { Entity, Column } from 'typeorm';
|
||||||
import { BaseEntity } from './base.entity';
|
import { BaseEntity } from './base.entity';
|
||||||
|
import { DOWNLOAD_TASK_STATUS } from 'src/enums/downloadTaskStatus';
|
||||||
|
|
||||||
@Entity({ name: 'downloadTask' })
|
@Entity({ name: 'downloadTask' })
|
||||||
export class DownloadTask extends BaseEntity {
|
export class DownloadTask extends BaseEntity {
|
||||||
@ -35,4 +36,13 @@ export class DownloadTask extends BaseEntity {
|
|||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
params: string;
|
params: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
isDeleted: boolean;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
deletedAt: Date;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
status: DOWNLOAD_TASK_STATUS;
|
||||||
}
|
}
|
||||||
|
@ -27,4 +27,16 @@ export class MessagePushingTask extends BaseEntity {
|
|||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
ownerId: string;
|
ownerId: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
isDeleted: boolean;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
deletedAt: Date;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
operator: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
operatorId: string;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { Entity, Column } from 'typeorm';
|
import { Entity, Column } from 'typeorm';
|
||||||
import { SurveySchemaInterface } from '../interfaces/survey';
|
import { SurveySchemaInterface } from '../interfaces/survey';
|
||||||
import { BaseEntity } from './base.entity';
|
import { BaseEntity } from './base.entity';
|
||||||
|
import { RECORD_STATUS, RECORD_SUB_STATUS } from '../enums';
|
||||||
|
|
||||||
@Entity({ name: 'surveyPublish' })
|
@Entity({ name: 'surveyPublish' })
|
||||||
export class ResponseSchema extends BaseEntity {
|
export class ResponseSchema extends BaseEntity {
|
||||||
@ -15,4 +16,19 @@ export class ResponseSchema extends BaseEntity {
|
|||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
pageId: string;
|
pageId: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
curStatus: {
|
||||||
|
status: RECORD_STATUS;
|
||||||
|
date: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
subStatus: {
|
||||||
|
status: RECORD_SUB_STATUS;
|
||||||
|
date: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
isDeleted: boolean;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { Entity, Column, Index, ObjectIdColumn } from 'typeorm';
|
import { Entity, Column, Index, ObjectIdColumn } from 'typeorm';
|
||||||
import { ObjectId } from 'mongodb';
|
import { ObjectId } from 'mongodb';
|
||||||
import { BaseEntity } from './base.entity';
|
import { BaseEntity } from './base.entity';
|
||||||
|
import { SESSION_STATUS } from 'src/enums/surveySessionStatus';
|
||||||
|
|
||||||
@Entity({ name: 'session' })
|
@Entity({ name: 'session' })
|
||||||
export class Session extends BaseEntity {
|
export class Session extends BaseEntity {
|
||||||
@ -15,4 +16,7 @@ export class Session extends BaseEntity {
|
|||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
userId: string;
|
userId: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
status: SESSION_STATUS;
|
||||||
}
|
}
|
||||||
|
@ -19,4 +19,7 @@ export class SurveyHistory extends BaseEntity {
|
|||||||
username: string;
|
username: string;
|
||||||
_id: string;
|
_id: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@Column('string')
|
||||||
|
sessionId: string;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { Entity, Column } from 'typeorm';
|
import { Entity, Column, BeforeInsert } from 'typeorm';
|
||||||
import { BaseEntity } from './base.entity';
|
import { BaseEntity } from './base.entity';
|
||||||
|
import { RECORD_STATUS, RECORD_SUB_STATUS } from '../enums';
|
||||||
|
|
||||||
@Entity({ name: 'surveyMeta' })
|
@Entity({ name: 'surveyMeta' })
|
||||||
export class SurveyMeta extends BaseEntity {
|
export class SurveyMeta extends BaseEntity {
|
||||||
@ -18,6 +19,9 @@ export class SurveyMeta extends BaseEntity {
|
|||||||
@Column()
|
@Column()
|
||||||
creator: string;
|
creator: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
creatorId: string;
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
owner: string;
|
owner: string;
|
||||||
|
|
||||||
@ -32,4 +36,48 @@ export class SurveyMeta extends BaseEntity {
|
|||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
workspaceId: string;
|
workspaceId: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
curStatus: {
|
||||||
|
status: RECORD_STATUS;
|
||||||
|
date: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
subStatus: {
|
||||||
|
status: RECORD_SUB_STATUS;
|
||||||
|
date: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
statusList: Array<{
|
||||||
|
status: RECORD_STATUS | RECORD_SUB_STATUS;
|
||||||
|
date: number;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
operator: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
operatorId: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
isDeleted: boolean;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
deletedAt: Date;
|
||||||
|
|
||||||
|
@BeforeInsert()
|
||||||
|
initDefaultInfo() {
|
||||||
|
const now = Date.now();
|
||||||
|
if (!this.curStatus) {
|
||||||
|
const curStatus = { status: RECORD_STATUS.NEW, date: now };
|
||||||
|
this.curStatus = curStatus;
|
||||||
|
this.statusList = [curStatus];
|
||||||
|
}
|
||||||
|
if (!this.subStatus) {
|
||||||
|
const subStatus = { status: RECORD_SUB_STATUS.DEFAULT, date: now };
|
||||||
|
this.subStatus = subStatus;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,33 @@ import { BaseEntity } from './base.entity';
|
|||||||
|
|
||||||
@Entity({ name: 'workspace' })
|
@Entity({ name: 'workspace' })
|
||||||
export class Workspace extends BaseEntity {
|
export class Workspace extends BaseEntity {
|
||||||
|
@Column()
|
||||||
|
creatorId: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
creator: string;
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
ownerId: string;
|
ownerId: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
owner: string;
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
name: string;
|
name: string;
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
description: string;
|
description: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
operator: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
operatorId: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
isDeleted: boolean;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
deletedAt: Date;
|
||||||
}
|
}
|
||||||
|
@ -11,4 +11,16 @@ export class WorkspaceMember extends BaseEntity {
|
|||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
role: string;
|
role: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
creator: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
creatorId: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
operator: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
operatorId: string;
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ import { UserService } from '../services/user.service';
|
|||||||
import { User } from 'src/models/user.entity';
|
import { User } from 'src/models/user.entity';
|
||||||
import { HttpException } from 'src/exceptions/httpException';
|
import { HttpException } from 'src/exceptions/httpException';
|
||||||
import { hash256 } from 'src/utils/hash256';
|
import { hash256 } from 'src/utils/hash256';
|
||||||
import { RECORD_STATUS } from 'src/enums';
|
|
||||||
import { ObjectId } from 'mongodb';
|
import { ObjectId } from 'mongodb';
|
||||||
|
|
||||||
describe('UserService', () => {
|
describe('UserService', () => {
|
||||||
@ -145,7 +144,6 @@ describe('UserService', () => {
|
|||||||
expect(userRepository.findOne).toHaveBeenCalledWith({
|
expect(userRepository.findOne).toHaveBeenCalledWith({
|
||||||
where: {
|
where: {
|
||||||
username: username,
|
username: username,
|
||||||
'curStatus.status': { $ne: RECORD_STATUS.REMOVED },
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
expect(user).toEqual(userInfo);
|
expect(user).toEqual(userInfo);
|
||||||
@ -163,7 +161,6 @@ describe('UserService', () => {
|
|||||||
expect(findOneSpy).toHaveBeenCalledWith({
|
expect(findOneSpy).toHaveBeenCalledWith({
|
||||||
where: {
|
where: {
|
||||||
username: username,
|
username: username,
|
||||||
'curStatus.status': { $ne: RECORD_STATUS.REMOVED },
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
expect(user).toBe(null);
|
expect(user).toBe(null);
|
||||||
@ -184,7 +181,6 @@ describe('UserService', () => {
|
|||||||
expect(userRepository.findOne).toHaveBeenCalledWith({
|
expect(userRepository.findOne).toHaveBeenCalledWith({
|
||||||
where: {
|
where: {
|
||||||
_id: new ObjectId(id),
|
_id: new ObjectId(id),
|
||||||
'curStatus.status': { $ne: RECORD_STATUS.REMOVED },
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
expect(user).toEqual(userInfo);
|
expect(user).toEqual(userInfo);
|
||||||
@ -202,7 +198,6 @@ describe('UserService', () => {
|
|||||||
expect(findOneSpy).toHaveBeenCalledWith({
|
expect(findOneSpy).toHaveBeenCalledWith({
|
||||||
where: {
|
where: {
|
||||||
_id: new ObjectId(id),
|
_id: new ObjectId(id),
|
||||||
'curStatus.status': { $ne: RECORD_STATUS.REMOVED },
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
expect(user).toBe(null);
|
expect(user).toBe(null);
|
||||||
@ -228,7 +223,6 @@ describe('UserService', () => {
|
|||||||
expect(userRepository.find).toHaveBeenCalledWith({
|
expect(userRepository.find).toHaveBeenCalledWith({
|
||||||
where: {
|
where: {
|
||||||
username: new RegExp(username),
|
username: new RegExp(username),
|
||||||
'curStatus.status': { $ne: RECORD_STATUS.REMOVED },
|
|
||||||
},
|
},
|
||||||
skip: 0,
|
skip: 0,
|
||||||
take: 10,
|
take: 10,
|
||||||
@ -263,7 +257,6 @@ describe('UserService', () => {
|
|||||||
_id: {
|
_id: {
|
||||||
$in: idList.map((id) => new ObjectId(id)),
|
$in: idList.map((id) => new ObjectId(id)),
|
||||||
},
|
},
|
||||||
'curStatus.status': { $ne: RECORD_STATUS.REMOVED },
|
|
||||||
},
|
},
|
||||||
select: ['_id', 'username', 'createDate'],
|
select: ['_id', 'username', 'createDate'],
|
||||||
});
|
});
|
||||||
|
@ -5,7 +5,6 @@ import { User } from 'src/models/user.entity';
|
|||||||
import { HttpException } from 'src/exceptions/httpException';
|
import { HttpException } from 'src/exceptions/httpException';
|
||||||
import { EXCEPTION_CODE } from 'src/enums/exceptionCode';
|
import { EXCEPTION_CODE } from 'src/enums/exceptionCode';
|
||||||
import { hash256 } from 'src/utils/hash256';
|
import { hash256 } from 'src/utils/hash256';
|
||||||
import { RECORD_STATUS } from 'src/enums';
|
|
||||||
import { ObjectId } from 'mongodb';
|
import { ObjectId } from 'mongodb';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@ -53,9 +52,6 @@ export class UserService {
|
|||||||
const user = await this.userRepository.findOne({
|
const user = await this.userRepository.findOne({
|
||||||
where: {
|
where: {
|
||||||
username: username,
|
username: username,
|
||||||
'curStatus.status': {
|
|
||||||
$ne: RECORD_STATUS.REMOVED,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -66,9 +62,6 @@ export class UserService {
|
|||||||
const user = await this.userRepository.findOne({
|
const user = await this.userRepository.findOne({
|
||||||
where: {
|
where: {
|
||||||
_id: new ObjectId(id),
|
_id: new ObjectId(id),
|
||||||
'curStatus.status': {
|
|
||||||
$ne: RECORD_STATUS.REMOVED,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -79,13 +72,10 @@ export class UserService {
|
|||||||
const list = await this.userRepository.find({
|
const list = await this.userRepository.find({
|
||||||
where: {
|
where: {
|
||||||
username: new RegExp(username),
|
username: new RegExp(username),
|
||||||
'curStatus.status': {
|
|
||||||
$ne: RECORD_STATUS.REMOVED,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
skip,
|
skip,
|
||||||
take,
|
take,
|
||||||
select: ['_id', 'username', 'createDate'],
|
select: ['_id', 'username', 'createdAt'],
|
||||||
});
|
});
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
@ -96,11 +86,8 @@ export class UserService {
|
|||||||
_id: {
|
_id: {
|
||||||
$in: idList.map((item) => new ObjectId(item)),
|
$in: idList.map((item) => new ObjectId(item)),
|
||||||
},
|
},
|
||||||
'curStatus.status': {
|
|
||||||
$ne: RECORD_STATUS.REMOVED,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
select: ['_id', 'username', 'createDate'],
|
select: ['_id', 'username', 'createdAt'],
|
||||||
});
|
});
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,6 @@ import { MessagePushingLogService } from '../services/messagePushingLog.service'
|
|||||||
import { CreateMessagePushingTaskDto } from '../dto/createMessagePushingTask.dto';
|
import { CreateMessagePushingTaskDto } from '../dto/createMessagePushingTask.dto';
|
||||||
import { UpdateMessagePushingTaskDto } from '../dto/updateMessagePushingTask.dto';
|
import { UpdateMessagePushingTaskDto } from '../dto/updateMessagePushingTask.dto';
|
||||||
|
|
||||||
import { RECORD_STATUS } from 'src/enums';
|
|
||||||
import { MESSAGE_PUSHING_TYPE } from 'src/enums/messagePushing';
|
import { MESSAGE_PUSHING_TYPE } from 'src/enums/messagePushing';
|
||||||
import { MESSAGE_PUSHING_HOOK } from 'src/enums/messagePushing';
|
import { MESSAGE_PUSHING_HOOK } from 'src/enums/messagePushing';
|
||||||
import { MessagePushingTask } from 'src/models/messagePushingTask.entity';
|
import { MessagePushingTask } from 'src/models/messagePushingTask.entity';
|
||||||
@ -121,7 +120,6 @@ describe('MessagePushingTaskService', () => {
|
|||||||
ownerId: mockOwnerId,
|
ownerId: mockOwnerId,
|
||||||
surveys: { $all: [surveyId] },
|
surveys: { $all: [surveyId] },
|
||||||
triggerHook: hook,
|
triggerHook: hook,
|
||||||
'curStatus.status': { $ne: RECORD_STATUS.REMOVED },
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -146,7 +144,6 @@ describe('MessagePushingTaskService', () => {
|
|||||||
where: {
|
where: {
|
||||||
ownerId: mockOwnerId,
|
ownerId: mockOwnerId,
|
||||||
_id: new ObjectId(taskId),
|
_id: new ObjectId(taskId),
|
||||||
'curStatus.status': { $ne: RECORD_STATUS.REMOVED },
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -161,10 +158,6 @@ describe('MessagePushingTaskService', () => {
|
|||||||
pushAddress: 'http://update.example.com',
|
pushAddress: 'http://update.example.com',
|
||||||
triggerHook: MESSAGE_PUSHING_HOOK.RESPONSE_INSERTED,
|
triggerHook: MESSAGE_PUSHING_HOOK.RESPONSE_INSERTED,
|
||||||
surveys: ['new survey id'],
|
surveys: ['new survey id'],
|
||||||
curStatus: {
|
|
||||||
status: RECORD_STATUS.EDITING,
|
|
||||||
date: Date.now(),
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
const existingTask = new MessagePushingTask();
|
const existingTask = new MessagePushingTask();
|
||||||
existingTask._id = new ObjectId(taskId);
|
existingTask._id = new ObjectId(taskId);
|
||||||
@ -197,34 +190,26 @@ describe('MessagePushingTaskService', () => {
|
|||||||
const taskId = '65afc62904d5db18534c0f78';
|
const taskId = '65afc62904d5db18534c0f78';
|
||||||
|
|
||||||
const updateResult = { modifiedCount: 1 };
|
const updateResult = { modifiedCount: 1 };
|
||||||
const mockOwnerId = '66028642292c50f8b71a9eee';
|
const mockOperatorId = '66028642292c50f8b71a9eee';
|
||||||
|
const mockOperator = 'mockOperator';
|
||||||
|
|
||||||
jest.spyOn(repository, 'updateOne').mockResolvedValue(updateResult);
|
jest.spyOn(repository, 'updateOne').mockResolvedValue(updateResult);
|
||||||
|
|
||||||
const result = await service.remove({
|
const result = await service.remove({
|
||||||
id: taskId,
|
id: taskId,
|
||||||
ownerId: mockOwnerId,
|
operatorId: mockOperatorId,
|
||||||
|
operator: mockOperator,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(result).toEqual(updateResult);
|
expect(result).toEqual(updateResult);
|
||||||
expect(repository.updateOne).toHaveBeenCalledWith(
|
expect(repository.updateOne).toHaveBeenCalledWith(
|
||||||
{
|
{
|
||||||
ownerId: mockOwnerId,
|
ownerId: mockOperatorId,
|
||||||
_id: new ObjectId(taskId),
|
_id: new ObjectId(taskId),
|
||||||
'curStatus.status': { $ne: RECORD_STATUS.REMOVED },
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
$set: {
|
$set: {
|
||||||
curStatus: {
|
isDeleted: true,
|
||||||
status: RECORD_STATUS.REMOVED,
|
|
||||||
date: expect.any(Number),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
$push: {
|
|
||||||
statusList: {
|
|
||||||
status: RECORD_STATUS.REMOVED,
|
|
||||||
date: expect.any(Number),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -150,8 +150,9 @@ export class MessagePushingTaskController {
|
|||||||
async remove(@Request() req, @Param('id') id: string) {
|
async remove(@Request() req, @Param('id') id: string) {
|
||||||
const userId = req.user._id;
|
const userId = req.user._id;
|
||||||
const res = await this.messagePushingTaskService.remove({
|
const res = await this.messagePushingTaskService.remove({
|
||||||
ownerId: userId,
|
|
||||||
id,
|
id,
|
||||||
|
operator: req.user.username,
|
||||||
|
operatorId: userId,
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
code: 200,
|
code: 200,
|
||||||
|
@ -4,7 +4,6 @@ import {
|
|||||||
MESSAGE_PUSHING_TYPE,
|
MESSAGE_PUSHING_TYPE,
|
||||||
MESSAGE_PUSHING_HOOK,
|
MESSAGE_PUSHING_HOOK,
|
||||||
} from 'src/enums/messagePushing';
|
} from 'src/enums/messagePushing';
|
||||||
import { RECORD_STATUS } from 'src/enums';
|
|
||||||
|
|
||||||
export class MessagePushingTaskDto {
|
export class MessagePushingTaskDto {
|
||||||
@ApiProperty({ description: '任务id' })
|
@ApiProperty({ description: '任务id' })
|
||||||
@ -27,12 +26,6 @@ export class MessagePushingTaskDto {
|
|||||||
|
|
||||||
@ApiProperty({ description: '所有者' })
|
@ApiProperty({ description: '所有者' })
|
||||||
owner: string;
|
owner: string;
|
||||||
|
|
||||||
@ApiProperty({ description: '任务状态', required: false })
|
|
||||||
curStatus?: {
|
|
||||||
status: RECORD_STATUS;
|
|
||||||
date: number;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CodeDto {
|
export class CodeDto {
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { ApiProperty } from '@nestjs/swagger';
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
import { RECORD_STATUS } from 'src/enums';
|
|
||||||
import {
|
import {
|
||||||
MESSAGE_PUSHING_TYPE,
|
MESSAGE_PUSHING_TYPE,
|
||||||
MESSAGE_PUSHING_HOOK,
|
MESSAGE_PUSHING_HOOK,
|
||||||
@ -20,10 +19,4 @@ export class UpdateMessagePushingTaskDto {
|
|||||||
|
|
||||||
@ApiProperty({ description: '绑定的问卷id', required: false })
|
@ApiProperty({ description: '绑定的问卷id', required: false })
|
||||||
surveys?: string[];
|
surveys?: string[];
|
||||||
|
|
||||||
@ApiProperty({ description: '任务状态', required: false })
|
|
||||||
curStatus?: {
|
|
||||||
status: RECORD_STATUS;
|
|
||||||
date: number;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ import { MESSAGE_PUSHING_HOOK } from 'src/enums/messagePushing';
|
|||||||
import { CreateMessagePushingTaskDto } from '../dto/createMessagePushingTask.dto';
|
import { CreateMessagePushingTaskDto } from '../dto/createMessagePushingTask.dto';
|
||||||
import { UpdateMessagePushingTaskDto } from '../dto/updateMessagePushingTask.dto';
|
import { UpdateMessagePushingTaskDto } from '../dto/updateMessagePushingTask.dto';
|
||||||
import { ObjectId } from 'mongodb';
|
import { ObjectId } from 'mongodb';
|
||||||
import { RECORD_STATUS } from 'src/enums';
|
|
||||||
import { MESSAGE_PUSHING_TYPE } from 'src/enums/messagePushing';
|
import { MESSAGE_PUSHING_TYPE } from 'src/enums/messagePushing';
|
||||||
import { MessagePushingLogService } from './messagePushingLog.service';
|
import { MessagePushingLogService } from './messagePushingLog.service';
|
||||||
import { httpPost } from 'src/utils/request';
|
import { httpPost } from 'src/utils/request';
|
||||||
@ -44,8 +43,8 @@ export class MessagePushingTaskService {
|
|||||||
ownerId?: string;
|
ownerId?: string;
|
||||||
}): Promise<MessagePushingTask[]> {
|
}): Promise<MessagePushingTask[]> {
|
||||||
const where: Record<string, any> = {
|
const where: Record<string, any> = {
|
||||||
'curStatus.status': {
|
isDeleted: {
|
||||||
$ne: RECORD_STATUS.REMOVED,
|
$ne: true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
if (surveyId) {
|
if (surveyId) {
|
||||||
@ -75,8 +74,8 @@ export class MessagePushingTaskService {
|
|||||||
where: {
|
where: {
|
||||||
ownerId,
|
ownerId,
|
||||||
_id: new ObjectId(id),
|
_id: new ObjectId(id),
|
||||||
'curStatus.status': {
|
isDeleted: {
|
||||||
$ne: RECORD_STATUS.REMOVED,
|
$ne: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -104,25 +103,25 @@ export class MessagePushingTaskService {
|
|||||||
return await this.messagePushingTaskRepository.save(updatedTask);
|
return await this.messagePushingTaskRepository.save(updatedTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
async remove({ id, ownerId }: { id: string; ownerId: string }) {
|
async remove({
|
||||||
const curStatus = {
|
id,
|
||||||
status: RECORD_STATUS.REMOVED,
|
operator,
|
||||||
date: Date.now(),
|
operatorId,
|
||||||
};
|
}: {
|
||||||
|
id: string;
|
||||||
|
operator: string;
|
||||||
|
operatorId: string;
|
||||||
|
}) {
|
||||||
return this.messagePushingTaskRepository.updateOne(
|
return this.messagePushingTaskRepository.updateOne(
|
||||||
{
|
{
|
||||||
ownerId,
|
|
||||||
_id: new ObjectId(id),
|
_id: new ObjectId(id),
|
||||||
'curStatus.status': {
|
|
||||||
$ne: RECORD_STATUS.REMOVED,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
$set: {
|
$set: {
|
||||||
curStatus,
|
isDeleted: true,
|
||||||
},
|
operator,
|
||||||
$push: {
|
operatorId,
|
||||||
statusList: curStatus as never,
|
deletedAt: new Date(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -147,6 +146,9 @@ export class MessagePushingTaskService {
|
|||||||
$push: {
|
$push: {
|
||||||
surveys: surveyId as never,
|
surveys: surveyId as never,
|
||||||
},
|
},
|
||||||
|
$set: {
|
||||||
|
updatedAt: new Date(),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -233,7 +233,7 @@ describe('DataStatisticController', () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
baseConf: {
|
baseConf: {
|
||||||
begTime: '2024-05-31 20:31:36',
|
beginTime: '2024-05-31 20:31:36',
|
||||||
endTime: '2034-05-31 20:31:36',
|
endTime: '2034-05-31 20:31:36',
|
||||||
language: 'chinese',
|
language: 'chinese',
|
||||||
showVoteProcess: 'allow',
|
showVoteProcess: 'allow',
|
||||||
|
@ -118,7 +118,6 @@ describe('DownloadTaskService', () => {
|
|||||||
expect(downloadTaskRepository.findAndCount).toHaveBeenCalledWith({
|
expect(downloadTaskRepository.findAndCount).toHaveBeenCalledWith({
|
||||||
where: {
|
where: {
|
||||||
creatorId: mockCreatorId,
|
creatorId: mockCreatorId,
|
||||||
'curStatus.status': { $ne: RECORD_STATUS.REMOVED },
|
|
||||||
},
|
},
|
||||||
take: 10,
|
take: 10,
|
||||||
skip: 0,
|
skip: 0,
|
||||||
|
@ -32,7 +32,7 @@ export const mockSensitiveResponseSchema: ResponseSchema = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
baseConf: {
|
baseConf: {
|
||||||
begTime: '2024-03-14 14:54:41',
|
beginTime: '2024-03-14 14:54:41',
|
||||||
endTime: '2034-03-14 14:54:41',
|
endTime: '2034-03-14 14:54:41',
|
||||||
language: 'chinese',
|
language: 'chinese',
|
||||||
tLimit: 0,
|
tLimit: 0,
|
||||||
@ -300,7 +300,7 @@ export const mockSensitiveResponseSchema: ResponseSchema = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
pageId: '65f29f3192862d6a9067ad1c',
|
pageId: '65f29f3192862d6a9067ad1c',
|
||||||
} as ResponseSchema;
|
} as unknown as ResponseSchema;
|
||||||
|
|
||||||
export const mockResponseSchema: ResponseSchema = {
|
export const mockResponseSchema: ResponseSchema = {
|
||||||
_id: new ObjectId('65b0d46e04d5db18534c0f7c'),
|
_id: new ObjectId('65b0d46e04d5db18534c0f7c'),
|
||||||
@ -331,7 +331,7 @@ export const mockResponseSchema: ResponseSchema = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
baseConf: {
|
baseConf: {
|
||||||
begTime: '2024-01-23 21:59:05',
|
beginTime: '2024-01-23 21:59:05',
|
||||||
endTime: '2034-01-23 21:59:05',
|
endTime: '2034-01-23 21:59:05',
|
||||||
language: 'chinese',
|
language: 'chinese',
|
||||||
tLimit: 0,
|
tLimit: 0,
|
||||||
@ -666,4 +666,4 @@ export const mockResponseSchema: ResponseSchema = {
|
|||||||
pageId: '65afc62904d5db18534c0f78',
|
pageId: '65afc62904d5db18534c0f78',
|
||||||
createDate: 1710340841289,
|
createDate: 1710340841289,
|
||||||
updateDate: 1710340841289.0,
|
updateDate: 1710340841289.0,
|
||||||
} as ResponseSchema;
|
} as unknown as ResponseSchema;
|
||||||
|
@ -172,7 +172,7 @@ describe('SurveyController', () => {
|
|||||||
bannerConfig: {},
|
bannerConfig: {},
|
||||||
},
|
},
|
||||||
baseConf: {
|
baseConf: {
|
||||||
begTime: '2024-01-23 21:59:05',
|
beginTime: '2024-01-23 21:59:05',
|
||||||
endTime: '2034-01-23 21:59:05',
|
endTime: '2034-01-23 21:59:05',
|
||||||
},
|
},
|
||||||
bottomConf: { logoImage: '/imgs/Logo.webp', logoImageWidth: '60%' },
|
bottomConf: { logoImage: '/imgs/Logo.webp', logoImageWidth: '60%' },
|
||||||
|
@ -42,7 +42,7 @@ describe('SurveyHistoryService', () => {
|
|||||||
msgContent: undefined,
|
msgContent: undefined,
|
||||||
},
|
},
|
||||||
baseConf: {
|
baseConf: {
|
||||||
begTime: '',
|
beginTime: '',
|
||||||
endTime: '',
|
endTime: '',
|
||||||
answerBegTime: '',
|
answerBegTime: '',
|
||||||
answerEndTime: '',
|
answerEndTime: '',
|
||||||
|
@ -121,6 +121,9 @@ describe('SurveyMetaController', () => {
|
|||||||
curStatus: {
|
curStatus: {
|
||||||
date: date,
|
date: date,
|
||||||
},
|
},
|
||||||
|
subStatus: {
|
||||||
|
date: date,
|
||||||
|
},
|
||||||
surveyType: 'normal',
|
surveyType: 'normal',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -138,14 +141,16 @@ describe('SurveyMetaController', () => {
|
|||||||
createDate: expect.stringMatching(
|
createDate: expect.stringMatching(
|
||||||
/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/,
|
/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/,
|
||||||
),
|
),
|
||||||
updateDate: expect.stringMatching(
|
|
||||||
/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/,
|
|
||||||
),
|
|
||||||
curStatus: expect.objectContaining({
|
curStatus: expect.objectContaining({
|
||||||
date: expect.stringMatching(
|
date: expect.stringMatching(
|
||||||
/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/,
|
/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/,
|
||||||
),
|
),
|
||||||
}),
|
}),
|
||||||
|
subStatus: expect.objectContaining({
|
||||||
|
date: expect.stringMatching(
|
||||||
|
/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/,
|
||||||
|
),
|
||||||
|
}),
|
||||||
surveyType: 'normal',
|
surveyType: 'normal',
|
||||||
}),
|
}),
|
||||||
]),
|
]),
|
||||||
|
@ -4,7 +4,7 @@ import { MongoRepository } from 'typeorm';
|
|||||||
import { SurveyMeta } from 'src/models/surveyMeta.entity';
|
import { SurveyMeta } from 'src/models/surveyMeta.entity';
|
||||||
import { PluginManagerProvider } from 'src/securityPlugin/pluginManager.provider';
|
import { PluginManagerProvider } from 'src/securityPlugin/pluginManager.provider';
|
||||||
import { PluginManager } from 'src/securityPlugin/pluginManager';
|
import { PluginManager } from 'src/securityPlugin/pluginManager';
|
||||||
import { RECORD_STATUS } from 'src/enums';
|
import { RECORD_STATUS, RECORD_SUB_STATUS } from 'src/enums';
|
||||||
import { getRepositoryToken } from '@nestjs/typeorm';
|
import { getRepositoryToken } from '@nestjs/typeorm';
|
||||||
import { HttpException } from 'src/exceptions/httpException';
|
import { HttpException } from 'src/exceptions/httpException';
|
||||||
import { SurveyUtilPlugin } from 'src/securityPlugin/surveyUtilPlugin';
|
import { SurveyUtilPlugin } from 'src/securityPlugin/surveyUtilPlugin';
|
||||||
@ -98,6 +98,10 @@ describe('SurveyMetaService', () => {
|
|||||||
it('should edit a survey meta and return it if in NEW or EDITING status', async () => {
|
it('should edit a survey meta and return it if in NEW or EDITING status', async () => {
|
||||||
const survey = new SurveyMeta();
|
const survey = new SurveyMeta();
|
||||||
survey.curStatus = { status: RECORD_STATUS.PUBLISHED, date: Date.now() };
|
survey.curStatus = { status: RECORD_STATUS.PUBLISHED, date: Date.now() };
|
||||||
|
survey.subStatus = {
|
||||||
|
status: RECORD_SUB_STATUS.DEFAULT,
|
||||||
|
date: Date.now(),
|
||||||
|
};
|
||||||
survey.statusList = [];
|
survey.statusList = [];
|
||||||
jest.spyOn(surveyRepository, 'save').mockResolvedValue(survey);
|
jest.spyOn(surveyRepository, 'save').mockResolvedValue(survey);
|
||||||
|
|
||||||
@ -116,6 +120,10 @@ describe('SurveyMetaService', () => {
|
|||||||
// 准备假的SurveyMeta对象
|
// 准备假的SurveyMeta对象
|
||||||
const survey = new SurveyMeta();
|
const survey = new SurveyMeta();
|
||||||
survey.curStatus = { status: RECORD_STATUS.NEW, date: Date.now() };
|
survey.curStatus = { status: RECORD_STATUS.NEW, date: Date.now() };
|
||||||
|
survey.subStatus = {
|
||||||
|
status: RECORD_SUB_STATUS.DEFAULT,
|
||||||
|
date: Date.now(),
|
||||||
|
};
|
||||||
survey.statusList = [];
|
survey.statusList = [];
|
||||||
|
|
||||||
// 模拟save方法
|
// 模拟save方法
|
||||||
@ -126,7 +134,7 @@ describe('SurveyMetaService', () => {
|
|||||||
|
|
||||||
// 验证结果
|
// 验证结果
|
||||||
expect(result).toBe(survey);
|
expect(result).toBe(survey);
|
||||||
expect(survey.curStatus.status).toBe(RECORD_STATUS.REMOVED);
|
expect(survey.subStatus.status).toBe(RECORD_STATUS.REMOVED);
|
||||||
expect(survey.statusList.length).toBe(1);
|
expect(survey.statusList.length).toBe(1);
|
||||||
expect(survey.statusList[0].status).toBe(RECORD_STATUS.REMOVED);
|
expect(survey.statusList[0].status).toBe(RECORD_STATUS.REMOVED);
|
||||||
expect(surveyRepository.save).toHaveBeenCalledTimes(1);
|
expect(surveyRepository.save).toHaveBeenCalledTimes(1);
|
||||||
@ -136,7 +144,10 @@ describe('SurveyMetaService', () => {
|
|||||||
it('should throw exception when survey is already removed', async () => {
|
it('should throw exception when survey is already removed', async () => {
|
||||||
// 准备假的SurveyMeta对象,其状态已设置为REMOVED
|
// 准备假的SurveyMeta对象,其状态已设置为REMOVED
|
||||||
const survey = new SurveyMeta();
|
const survey = new SurveyMeta();
|
||||||
survey.curStatus = { status: RECORD_STATUS.REMOVED, date: Date.now() };
|
survey.curStatus = {
|
||||||
|
status: RECORD_STATUS.REMOVED,
|
||||||
|
date: Date.now(),
|
||||||
|
};
|
||||||
|
|
||||||
// 调用要测试的方法并期待异常
|
// 调用要测试的方法并期待异常
|
||||||
await expect(service.deleteSurveyMeta(survey)).rejects.toThrow(
|
await expect(service.deleteSurveyMeta(survey)).rejects.toThrow(
|
||||||
@ -193,6 +204,10 @@ describe('SurveyMetaService', () => {
|
|||||||
status: RECORD_STATUS.PUBLISHED,
|
status: RECORD_STATUS.PUBLISHED,
|
||||||
date: expect.any(Number),
|
date: expect.any(Number),
|
||||||
},
|
},
|
||||||
|
subStatus: {
|
||||||
|
status: RECORD_SUB_STATUS.DEFAULT,
|
||||||
|
date: expect.any(Number),
|
||||||
|
},
|
||||||
} as unknown as SurveyMeta;
|
} as unknown as SurveyMeta;
|
||||||
|
|
||||||
jest.spyOn(surveyRepository, 'save').mockResolvedValue(savedSurveyMeta);
|
jest.spyOn(surveyRepository, 'save').mockResolvedValue(savedSurveyMeta);
|
||||||
|
@ -185,10 +185,14 @@ export class CollaboratorController {
|
|||||||
userIdList: newCollaboratorUserIdList,
|
userIdList: newCollaboratorUserIdList,
|
||||||
});
|
});
|
||||||
this.logger.info('batchDelete:' + JSON.stringify(delRes));
|
this.logger.info('batchDelete:' + JSON.stringify(delRes));
|
||||||
|
const username = req.user.username;
|
||||||
|
const userId = req.user._id.toString();
|
||||||
if (Array.isArray(newCollaborator) && newCollaborator.length > 0) {
|
if (Array.isArray(newCollaborator) && newCollaborator.length > 0) {
|
||||||
const insertRes = await this.collaboratorService.batchCreate({
|
const insertRes = await this.collaboratorService.batchCreate({
|
||||||
surveyId: value.surveyId,
|
surveyId: value.surveyId,
|
||||||
collaboratorList: newCollaborator,
|
collaboratorList: newCollaborator,
|
||||||
|
creator: username,
|
||||||
|
creatorId: userId,
|
||||||
});
|
});
|
||||||
this.logger.info(`${JSON.stringify(insertRes)}`);
|
this.logger.info(`${JSON.stringify(insertRes)}`);
|
||||||
}
|
}
|
||||||
@ -198,6 +202,8 @@ export class CollaboratorController {
|
|||||||
this.collaboratorService.updateById({
|
this.collaboratorService.updateById({
|
||||||
collaboratorId: item._id,
|
collaboratorId: item._id,
|
||||||
permissions: item.permissions,
|
permissions: item.permissions,
|
||||||
|
operator: username,
|
||||||
|
operatorId: userId,
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -98,7 +98,7 @@ export class DownloadTaskController {
|
|||||||
list: list.map((data) => {
|
list: list.map((data) => {
|
||||||
const item: Record<string, any> = {};
|
const item: Record<string, any> = {};
|
||||||
item.taskId = data._id.toString();
|
item.taskId = data._id.toString();
|
||||||
item.curStatus = data.curStatus;
|
item.status = data.status;
|
||||||
item.filename = data.filename;
|
item.filename = data.filename;
|
||||||
item.url = data.url;
|
item.url = data.url;
|
||||||
const fmt = 'YYYY-MM-DD HH:mm:ss';
|
const fmt = 'YYYY-MM-DD HH:mm:ss';
|
||||||
@ -114,7 +114,7 @@ export class DownloadTaskController {
|
|||||||
}
|
}
|
||||||
item.fileSize = `${size.toFixed()} ${units[unitIndex]}`;
|
item.fileSize = `${size.toFixed()} ${units[unitIndex]}`;
|
||||||
}
|
}
|
||||||
item.createDate = moment(Number(data.createDate)).format(fmt);
|
item.createdAt = moment(data.createdAt).format(fmt);
|
||||||
return item;
|
return item;
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
@ -177,6 +177,8 @@ export class DownloadTaskController {
|
|||||||
|
|
||||||
const delRes = await this.downloadTaskService.deleteDownloadTask({
|
const delRes = await this.downloadTaskService.deleteDownloadTask({
|
||||||
taskId,
|
taskId,
|
||||||
|
operator: req.user.username,
|
||||||
|
operatorId: req.user._id.toString(),
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -67,9 +67,9 @@ export class SessionController {
|
|||||||
|
|
||||||
@Post('/seize')
|
@Post('/seize')
|
||||||
@HttpCode(200)
|
@HttpCode(200)
|
||||||
@UseGuards(SurveyGuard)
|
@UseGuards(SessionGuard, SurveyGuard)
|
||||||
@UseGuards(SessionGuard)
|
|
||||||
@SetMetadata('sessionId', 'body.sessionId')
|
@SetMetadata('sessionId', 'body.sessionId')
|
||||||
|
@SetMetadata('surveyId', 'surveyId')
|
||||||
@SetMetadata('surveyPermission', [SURVEY_PERMISSION.SURVEY_CONF_MANAGE])
|
@SetMetadata('surveyPermission', [SURVEY_PERMISSION.SURVEY_CONF_MANAGE])
|
||||||
@UseGuards(Authentication)
|
@UseGuards(Authentication)
|
||||||
async seize(
|
async seize(
|
||||||
|
@ -144,7 +144,7 @@ export class SurveyController {
|
|||||||
|
|
||||||
if (latestEditingOne && latestEditingOne._id.toString() !== sessionId) {
|
if (latestEditingOne && latestEditingOne._id.toString() !== sessionId) {
|
||||||
const curSession = await this.sessionService.findOne(sessionId);
|
const curSession = await this.sessionService.findOne(sessionId);
|
||||||
if (curSession.createDate <= latestEditingOne.updateDate) {
|
if (curSession.createdAt <= latestEditingOne.updatedAt) {
|
||||||
// 在当前用户打开之后,被其他页面保存过了
|
// 在当前用户打开之后,被其他页面保存过了
|
||||||
const isSameOperator =
|
const isSameOperator =
|
||||||
latestEditingOne.userId === req.user._id.toString();
|
latestEditingOne.userId === req.user._id.toString();
|
||||||
@ -194,8 +194,35 @@ export class SurveyController {
|
|||||||
async deleteSurvey(@Request() req) {
|
async deleteSurvey(@Request() req) {
|
||||||
const surveyMeta = req.surveyMeta;
|
const surveyMeta = req.surveyMeta;
|
||||||
|
|
||||||
await this.surveyMetaService.deleteSurveyMeta(surveyMeta);
|
const delMetaRes = await this.surveyMetaService.deleteSurveyMeta({
|
||||||
await this.responseSchemaService.deleteResponseSchema({
|
surveyId: surveyMeta._id.toString(),
|
||||||
|
operator: req.user.username,
|
||||||
|
operatorId: req.user._id.toString(),
|
||||||
|
});
|
||||||
|
const delResponseRes =
|
||||||
|
await this.responseSchemaService.deleteResponseSchema({
|
||||||
|
surveyPath: surveyMeta.surveyPath,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.logger.info(JSON.stringify(delMetaRes));
|
||||||
|
this.logger.info(JSON.stringify(delResponseRes));
|
||||||
|
|
||||||
|
return {
|
||||||
|
code: 200,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@HttpCode(200)
|
||||||
|
@Post('/pausingSurvey')
|
||||||
|
@UseGuards(SurveyGuard)
|
||||||
|
@SetMetadata('surveyId', 'body.surveyId')
|
||||||
|
@SetMetadata('surveyPermission', [SURVEY_PERMISSION.SURVEY_CONF_MANAGE])
|
||||||
|
@UseGuards(Authentication)
|
||||||
|
async pausingSurvey(@Request() req) {
|
||||||
|
const surveyMeta = req.surveyMeta;
|
||||||
|
|
||||||
|
await this.surveyMetaService.pausingSurveyMeta(surveyMeta);
|
||||||
|
await this.responseSchemaService.pausingResponseSchema({
|
||||||
surveyPath: surveyMeta.surveyPath,
|
surveyPath: surveyMeta.surveyPath,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -305,6 +332,12 @@ export class SurveyController {
|
|||||||
const username = req.user.username;
|
const username = req.user.username;
|
||||||
const surveyId = value.surveyId;
|
const surveyId = value.surveyId;
|
||||||
const surveyMeta = req.surveyMeta;
|
const surveyMeta = req.surveyMeta;
|
||||||
|
if (surveyMeta.isDeleted) {
|
||||||
|
throw new HttpException(
|
||||||
|
'问卷已删除,无法发布',
|
||||||
|
EXCEPTION_CODE.SURVEY_NOT_FOUND,
|
||||||
|
);
|
||||||
|
}
|
||||||
const surveyConf =
|
const surveyConf =
|
||||||
await this.surveyConfService.getSurveyConfBySurveyId(surveyId);
|
await this.surveyConfService.getSurveyConfBySurveyId(surveyId);
|
||||||
|
|
||||||
@ -330,7 +363,8 @@ export class SurveyController {
|
|||||||
pageId: surveyId,
|
pageId: surveyId,
|
||||||
});
|
});
|
||||||
|
|
||||||
await this.surveyHistoryService.addHistory({
|
// 添加发布历史可以异步添加
|
||||||
|
this.surveyHistoryService.addHistory({
|
||||||
surveyId,
|
surveyId,
|
||||||
schema: surveyConf.code,
|
schema: surveyConf.code,
|
||||||
type: HISTORY_TYPE.PUBLISH_HIS,
|
type: HISTORY_TYPE.PUBLISH_HIS,
|
||||||
|
@ -18,7 +18,7 @@ import { Logger } from 'src/logger';
|
|||||||
import { HttpException } from 'src/exceptions/httpException';
|
import { HttpException } from 'src/exceptions/httpException';
|
||||||
import { EXCEPTION_CODE } from 'src/enums/exceptionCode';
|
import { EXCEPTION_CODE } from 'src/enums/exceptionCode';
|
||||||
@ApiTags('survey')
|
@ApiTags('survey')
|
||||||
@Controller('/api/surveyHisotry')
|
@Controller('/api/surveyHistory')
|
||||||
export class SurveyHistoryController {
|
export class SurveyHistoryController {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly surveyHistoryService: SurveyHistoryService,
|
private readonly surveyHistoryService: SurveyHistoryService,
|
||||||
|
@ -58,7 +58,11 @@ export class SurveyMetaController {
|
|||||||
survey.title = value.title;
|
survey.title = value.title;
|
||||||
survey.remark = value.remark;
|
survey.remark = value.remark;
|
||||||
|
|
||||||
await this.surveyMetaService.editSurveyMeta(survey);
|
await this.surveyMetaService.editSurveyMeta({
|
||||||
|
survey,
|
||||||
|
operator: req.user.username,
|
||||||
|
operatorId: req.user._id.toString(),
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
code: 200,
|
code: 200,
|
||||||
@ -127,9 +131,10 @@ export class SurveyMetaController {
|
|||||||
if (!item.surveyType) {
|
if (!item.surveyType) {
|
||||||
item.surveyType = item.questionType || 'normal';
|
item.surveyType = item.questionType || 'normal';
|
||||||
}
|
}
|
||||||
item.createDate = moment(item.createDate).format(fmt);
|
item.createdAt = moment(item.createdAt).format(fmt);
|
||||||
item.updateDate = moment(item.updateDate).format(fmt);
|
|
||||||
item.curStatus.date = moment(item.curStatus.date).format(fmt);
|
item.curStatus.date = moment(item.curStatus.date).format(fmt);
|
||||||
|
item.subStatus.date = moment(item.subStatus.date).format(fmt);
|
||||||
|
item.updatedAt = moment(item.updatedAt).format(fmt);
|
||||||
const surveyId = item._id.toString();
|
const surveyId = item._id.toString();
|
||||||
if (cooperSurveyIdMap[surveyId]) {
|
if (cooperSurveyIdMap[surveyId]) {
|
||||||
item.isCollaborated = true;
|
item.isCollaborated = true;
|
||||||
|
@ -22,12 +22,17 @@ export class CollaboratorService {
|
|||||||
return this.collaboratorRepository.save(collaborator);
|
return this.collaboratorRepository.save(collaborator);
|
||||||
}
|
}
|
||||||
|
|
||||||
async batchCreate({ surveyId, collaboratorList }) {
|
async batchCreate({ surveyId, collaboratorList, creator, creatorId }) {
|
||||||
|
const now = new Date();
|
||||||
const res = await this.collaboratorRepository.insertMany(
|
const res = await this.collaboratorRepository.insertMany(
|
||||||
collaboratorList.map((item) => {
|
collaboratorList.map((item) => {
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
surveyId,
|
surveyId,
|
||||||
|
createdAt: now,
|
||||||
|
updatedAt: now,
|
||||||
|
creator,
|
||||||
|
creatorId,
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
@ -60,7 +65,13 @@ export class CollaboratorService {
|
|||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
async changeUserPermission({ userId, surveyId, permission }) {
|
async changeUserPermission({
|
||||||
|
userId,
|
||||||
|
surveyId,
|
||||||
|
permission,
|
||||||
|
operator,
|
||||||
|
operatorId,
|
||||||
|
}) {
|
||||||
const updateRes = await this.collaboratorRepository.updateOne(
|
const updateRes = await this.collaboratorRepository.updateOne(
|
||||||
{
|
{
|
||||||
surveyId,
|
surveyId,
|
||||||
@ -69,6 +80,9 @@ export class CollaboratorService {
|
|||||||
{
|
{
|
||||||
$set: {
|
$set: {
|
||||||
permission,
|
permission,
|
||||||
|
operator,
|
||||||
|
operatorId,
|
||||||
|
updatedAt: new Date(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -134,7 +148,7 @@ export class CollaboratorService {
|
|||||||
return delRes;
|
return delRes;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateById({ collaboratorId, permissions }) {
|
updateById({ collaboratorId, permissions, operator, operatorId }) {
|
||||||
return this.collaboratorRepository.updateOne(
|
return this.collaboratorRepository.updateOne(
|
||||||
{
|
{
|
||||||
_id: new ObjectId(collaboratorId),
|
_id: new ObjectId(collaboratorId),
|
||||||
@ -142,6 +156,9 @@ export class CollaboratorService {
|
|||||||
{
|
{
|
||||||
$set: {
|
$set: {
|
||||||
permissions,
|
permissions,
|
||||||
|
operator,
|
||||||
|
operatorId,
|
||||||
|
updatedAt: new Date(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -34,8 +34,8 @@ export class DataStatisticService {
|
|||||||
const dataListMap = keyBy(dataList, 'field');
|
const dataListMap = keyBy(dataList, 'field');
|
||||||
const where = {
|
const where = {
|
||||||
pageId: surveyId,
|
pageId: surveyId,
|
||||||
'curStatus.status': {
|
isDeleted: {
|
||||||
$ne: 'removed',
|
$ne: true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const [surveyResponseList, total] =
|
const [surveyResponseList, total] =
|
||||||
@ -44,7 +44,7 @@ export class DataStatisticService {
|
|||||||
take: pageSize,
|
take: pageSize,
|
||||||
skip: (pageNum - 1) * pageSize,
|
skip: (pageNum - 1) * pageSize,
|
||||||
order: {
|
order: {
|
||||||
createDate: -1,
|
createdAt: -1,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -90,10 +90,10 @@ export class DataStatisticService {
|
|||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
...data,
|
...data,
|
||||||
diffTime: (submitedData.diffTime / 1000).toFixed(2),
|
diffTime: submitedData.diffTime
|
||||||
createDate: moment(submitedData.createDate).format(
|
? (submitedData.diffTime / 1000).toFixed(2)
|
||||||
'YYYY-MM-DD HH:mm:ss',
|
: '0',
|
||||||
),
|
createdAt: moment(submitedData.createdAt).format('YYYY-MM-DD HH:mm:ss'),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
@ -124,8 +124,8 @@ export class DataStatisticService {
|
|||||||
{
|
{
|
||||||
$match: {
|
$match: {
|
||||||
pageId: surveyId,
|
pageId: surveyId,
|
||||||
'curStatus.status': {
|
isDeleted: {
|
||||||
$ne: 'removed',
|
$ne: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -3,7 +3,6 @@ import { InjectRepository } from '@nestjs/typeorm';
|
|||||||
import { MongoRepository } from 'typeorm';
|
import { MongoRepository } from 'typeorm';
|
||||||
import { ResponseSchema } from 'src/models/responseSchema.entity';
|
import { ResponseSchema } from 'src/models/responseSchema.entity';
|
||||||
import { DownloadTask } from 'src/models/downloadTask.entity';
|
import { DownloadTask } from 'src/models/downloadTask.entity';
|
||||||
import { RECORD_STATUS } from 'src/enums';
|
|
||||||
import { ObjectId } from 'mongodb';
|
import { ObjectId } from 'mongodb';
|
||||||
import { ResponseSchemaService } from 'src/modules/surveyResponse/services/responseScheme.service';
|
import { ResponseSchemaService } from 'src/modules/surveyResponse/services/responseScheme.service';
|
||||||
import { SurveyResponse } from 'src/models/surveyResponse.entity';
|
import { SurveyResponse } from 'src/models/surveyResponse.entity';
|
||||||
@ -14,11 +13,12 @@ import { get } from 'lodash';
|
|||||||
import { FileService } from 'src/modules/file/services/file.service';
|
import { FileService } from 'src/modules/file/services/file.service';
|
||||||
import { Logger } from 'src/logger';
|
import { Logger } from 'src/logger';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
import { DOWNLOAD_TASK_STATUS } from 'src/enums/downloadTaskStatus';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DownloadTaskService {
|
export class DownloadTaskService {
|
||||||
static taskList: Array<any> = [];
|
private static taskList: Array<any> = [];
|
||||||
static isExecuting: boolean = false;
|
private static isExecuting: boolean = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@InjectRepository(DownloadTask)
|
@InjectRepository(DownloadTask)
|
||||||
@ -56,6 +56,7 @@ export class DownloadTaskService {
|
|||||||
title: responseSchema.title,
|
title: responseSchema.title,
|
||||||
},
|
},
|
||||||
filename,
|
filename,
|
||||||
|
status: DOWNLOAD_TASK_STATUS.WAITING,
|
||||||
});
|
});
|
||||||
await this.downloadTaskRepository.save(downloadTask);
|
await this.downloadTaskRepository.save(downloadTask);
|
||||||
return downloadTask._id.toString();
|
return downloadTask._id.toString();
|
||||||
@ -72,8 +73,8 @@ export class DownloadTaskService {
|
|||||||
}) {
|
}) {
|
||||||
const where = {
|
const where = {
|
||||||
creatorId,
|
creatorId,
|
||||||
'curStatus.status': {
|
isDeleted: {
|
||||||
$ne: RECORD_STATUS.REMOVED,
|
$ne: true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const [surveyDownloadList, total] =
|
const [surveyDownloadList, total] =
|
||||||
@ -82,7 +83,7 @@ export class DownloadTaskService {
|
|||||||
take: pageSize,
|
take: pageSize,
|
||||||
skip: (pageIndex - 1) * pageSize,
|
skip: (pageIndex - 1) * pageSize,
|
||||||
order: {
|
order: {
|
||||||
createDate: -1,
|
createdAt: -1,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
@ -103,24 +104,25 @@ export class DownloadTaskService {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteDownloadTask({ taskId }: { taskId: string }) {
|
async deleteDownloadTask({
|
||||||
const curStatus = {
|
taskId,
|
||||||
status: RECORD_STATUS.REMOVED,
|
operator,
|
||||||
date: Date.now(),
|
operatorId,
|
||||||
};
|
}: {
|
||||||
|
taskId: string;
|
||||||
|
operator: string;
|
||||||
|
operatorId: string;
|
||||||
|
}) {
|
||||||
return this.downloadTaskRepository.updateOne(
|
return this.downloadTaskRepository.updateOne(
|
||||||
{
|
{
|
||||||
_id: new ObjectId(taskId),
|
_id: new ObjectId(taskId),
|
||||||
'curStatus.status': {
|
|
||||||
$ne: RECORD_STATUS.REMOVED,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
$set: {
|
$set: {
|
||||||
curStatus,
|
isDeleted: true,
|
||||||
},
|
operator,
|
||||||
$push: {
|
operatorId,
|
||||||
statusList: curStatus as never,
|
deletedAt: new Date(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -140,7 +142,7 @@ export class DownloadTaskService {
|
|||||||
const taskId = DownloadTaskService.taskList.shift();
|
const taskId = DownloadTaskService.taskList.shift();
|
||||||
this.logger.info(`handle taskId: ${taskId}`);
|
this.logger.info(`handle taskId: ${taskId}`);
|
||||||
const taskInfo = await this.getDownloadTaskById({ taskId });
|
const taskInfo = await this.getDownloadTaskById({ taskId });
|
||||||
if (!taskInfo || taskInfo.curStatus.status === RECORD_STATUS.REMOVED) {
|
if (!taskInfo || taskInfo.isDeleted) {
|
||||||
// 不存在或者已删除的,不处理
|
// 不存在或者已删除的,不处理
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -160,10 +162,8 @@ export class DownloadTaskService {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
$set: {
|
$set: {
|
||||||
curStatus: {
|
status: DOWNLOAD_TASK_STATUS.COMPUTING,
|
||||||
status: RECORD_STATUS.COMPUTING,
|
updatedAt: new Date(),
|
||||||
date: Date.now(),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -176,9 +176,6 @@ export class DownloadTaskService {
|
|||||||
await this.responseSchemaService.getResponseSchemaByPageId(surveyId);
|
await this.responseSchemaService.getResponseSchemaByPageId(surveyId);
|
||||||
const where = {
|
const where = {
|
||||||
pageId: surveyId,
|
pageId: surveyId,
|
||||||
'curStatus.status': {
|
|
||||||
$ne: 'removed',
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
const total = await this.surveyResponseRepository.count(where);
|
const total = await this.surveyResponseRepository.count(where);
|
||||||
const pageSize = 200;
|
const pageSize = 200;
|
||||||
@ -205,9 +202,13 @@ export class DownloadTaskService {
|
|||||||
for (const headItem of listHead) {
|
for (const headItem of listHead) {
|
||||||
const field = headItem.field;
|
const field = headItem.field;
|
||||||
const val = get(bodyItem, field, '');
|
const val = get(bodyItem, field, '');
|
||||||
const $ = load(val);
|
if (typeof val === 'string') {
|
||||||
const text = $.text();
|
const $ = load(val);
|
||||||
bodyData.push(text);
|
const text = $.text();
|
||||||
|
bodyData.push(text);
|
||||||
|
} else {
|
||||||
|
bodyData.push(val);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
xlsxBody.push(bodyData);
|
xlsxBody.push(bodyData);
|
||||||
}
|
}
|
||||||
@ -236,11 +237,6 @@ export class DownloadTaskService {
|
|||||||
filename: taskInfo.filename,
|
filename: taskInfo.filename,
|
||||||
});
|
});
|
||||||
|
|
||||||
const curStatus = {
|
|
||||||
status: RECORD_STATUS.FINISHED,
|
|
||||||
date: Date.now(),
|
|
||||||
};
|
|
||||||
|
|
||||||
// 更新计算结果
|
// 更新计算结果
|
||||||
const updateFinishRes = await this.downloadTaskRepository.updateOne(
|
const updateFinishRes = await this.downloadTaskRepository.updateOne(
|
||||||
{
|
{
|
||||||
@ -248,32 +244,24 @@ export class DownloadTaskService {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
$set: {
|
$set: {
|
||||||
curStatus,
|
status: DOWNLOAD_TASK_STATUS.SUCCEED,
|
||||||
url,
|
url,
|
||||||
fileKey: key,
|
fileKey: key,
|
||||||
fileSize: buffer.length,
|
fileSize: buffer.length,
|
||||||
},
|
updatedAt: new Date(),
|
||||||
$push: {
|
|
||||||
statusList: curStatus as never,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
this.logger.info(JSON.stringify(updateFinishRes));
|
this.logger.info(JSON.stringify(updateFinishRes));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const curStatus = {
|
|
||||||
status: RECORD_STATUS.ERROR,
|
|
||||||
date: Date.now(),
|
|
||||||
};
|
|
||||||
await this.downloadTaskRepository.updateOne(
|
await this.downloadTaskRepository.updateOne(
|
||||||
{
|
{
|
||||||
_id: taskInfo._id,
|
_id: taskInfo._id,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
$set: {
|
$set: {
|
||||||
curStatus,
|
status: DOWNLOAD_TASK_STATUS.FAILED,
|
||||||
},
|
updatedAt: new Date(),
|
||||||
$push: {
|
|
||||||
statusList: curStatus as never,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -3,7 +3,7 @@ import { InjectRepository } from '@nestjs/typeorm';
|
|||||||
import { MongoRepository } from 'typeorm';
|
import { MongoRepository } from 'typeorm';
|
||||||
import { Session } from 'src/models/session.entity';
|
import { Session } from 'src/models/session.entity';
|
||||||
import { ObjectId } from 'mongodb';
|
import { ObjectId } from 'mongodb';
|
||||||
import { RECORD_STATUS } from 'src/enums';
|
import { SESSION_STATUS } from 'src/enums/surveySessionStatus';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SessionService {
|
export class SessionService {
|
||||||
@ -16,6 +16,7 @@ export class SessionService {
|
|||||||
const session = this.sessionRepository.create({
|
const session = this.sessionRepository.create({
|
||||||
surveyId,
|
surveyId,
|
||||||
userId,
|
userId,
|
||||||
|
status: SESSION_STATUS.DEACTIVATED,
|
||||||
});
|
});
|
||||||
return this.sessionRepository.save(session);
|
return this.sessionRepository.save(session);
|
||||||
}
|
}
|
||||||
@ -32,33 +33,20 @@ export class SessionService {
|
|||||||
return this.sessionRepository.findOne({
|
return this.sessionRepository.findOne({
|
||||||
where: {
|
where: {
|
||||||
surveyId,
|
surveyId,
|
||||||
'curStatus.status': {
|
status: SESSION_STATUS.ACTIVATED,
|
||||||
$ne: RECORD_STATUS.NEW,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
updateSessionToEditing({ sessionId, surveyId }) {
|
updateSessionToEditing({ sessionId, surveyId }) {
|
||||||
const now = Date.now();
|
|
||||||
const editingStatus = {
|
|
||||||
status: RECORD_STATUS.EDITING,
|
|
||||||
date: now,
|
|
||||||
};
|
|
||||||
const newStatus = {
|
|
||||||
status: RECORD_STATUS.NEW,
|
|
||||||
date: now,
|
|
||||||
};
|
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
this.sessionRepository.updateOne(
|
this.sessionRepository.update(
|
||||||
{
|
{
|
||||||
_id: new ObjectId(sessionId),
|
_id: new ObjectId(sessionId),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
$set: {
|
status: SESSION_STATUS.ACTIVATED,
|
||||||
curStatus: editingStatus,
|
updatedAt: new Date(),
|
||||||
updateDate: now,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
this.sessionRepository.updateMany(
|
this.sessionRepository.updateMany(
|
||||||
@ -70,8 +58,8 @@ export class SessionService {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
$set: {
|
$set: {
|
||||||
curStatus: newStatus,
|
status: SESSION_STATUS.DEACTIVATED,
|
||||||
updateDate: now,
|
updatedAt: new Date(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -45,9 +45,9 @@ export class SurveyHistoryService {
|
|||||||
},
|
},
|
||||||
take: 100,
|
take: 100,
|
||||||
order: {
|
order: {
|
||||||
createDate: -1,
|
createdAt: -1,
|
||||||
},
|
},
|
||||||
select: ['createDate', 'operator', 'type', '_id'],
|
select: ['createdAt', 'operator', 'type', '_id'],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common';
|
|||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
import { MongoRepository, FindOptionsOrder } from 'typeorm';
|
import { MongoRepository, FindOptionsOrder } from 'typeorm';
|
||||||
import { SurveyMeta } from 'src/models/surveyMeta.entity';
|
import { SurveyMeta } from 'src/models/surveyMeta.entity';
|
||||||
import { RECORD_STATUS } from 'src/enums';
|
import { RECORD_STATUS, RECORD_SUB_STATUS } from 'src/enums';
|
||||||
import { ObjectId } from 'mongodb';
|
import { ObjectId } from 'mongodb';
|
||||||
import { HttpException } from 'src/exceptions/httpException';
|
import { HttpException } from 'src/exceptions/httpException';
|
||||||
import { EXCEPTION_CODE } from 'src/enums/exceptionCode';
|
import { EXCEPTION_CODE } from 'src/enums/exceptionCode';
|
||||||
@ -65,6 +65,7 @@ export class SurveyMetaService {
|
|||||||
surveyType: surveyType,
|
surveyType: surveyType,
|
||||||
surveyPath,
|
surveyPath,
|
||||||
creator: username,
|
creator: username,
|
||||||
|
creatorId: userId,
|
||||||
owner: username,
|
owner: username,
|
||||||
ownerId: userId,
|
ownerId: userId,
|
||||||
createMethod,
|
createMethod,
|
||||||
@ -75,11 +76,36 @@ export class SurveyMetaService {
|
|||||||
return await this.surveyRepository.save(newSurvey);
|
return await this.surveyRepository.save(newSurvey);
|
||||||
}
|
}
|
||||||
|
|
||||||
async editSurveyMeta(survey: SurveyMeta) {
|
async pausingSurveyMeta(survey: SurveyMeta) {
|
||||||
if (
|
if (survey?.curStatus?.status === RECORD_STATUS.NEW) {
|
||||||
survey.curStatus.status !== RECORD_STATUS.NEW &&
|
throw new HttpException(
|
||||||
survey.curStatus.status !== RECORD_STATUS.EDITING
|
'问卷不能暂停',
|
||||||
) {
|
EXCEPTION_CODE.SURVEY_STATUS_TRANSFORM_ERROR,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const subCurStatus = {
|
||||||
|
status: RECORD_SUB_STATUS.PAUSING,
|
||||||
|
date: Date.now(),
|
||||||
|
};
|
||||||
|
survey.subStatus = subCurStatus;
|
||||||
|
if (Array.isArray(survey.statusList)) {
|
||||||
|
survey.statusList.push(subCurStatus);
|
||||||
|
} else {
|
||||||
|
survey.statusList = [subCurStatus];
|
||||||
|
}
|
||||||
|
return this.surveyRepository.save(survey);
|
||||||
|
}
|
||||||
|
|
||||||
|
async editSurveyMeta({
|
||||||
|
survey,
|
||||||
|
operator,
|
||||||
|
operatorId,
|
||||||
|
}: {
|
||||||
|
survey: SurveyMeta;
|
||||||
|
operator: string;
|
||||||
|
operatorId: string;
|
||||||
|
}) {
|
||||||
|
if (survey?.curStatus?.status !== RECORD_STATUS.EDITING) {
|
||||||
const newStatus = {
|
const newStatus = {
|
||||||
status: RECORD_STATUS.EDITING,
|
status: RECORD_STATUS.EDITING,
|
||||||
date: Date.now(),
|
date: Date.now(),
|
||||||
@ -87,27 +113,26 @@ export class SurveyMetaService {
|
|||||||
survey.curStatus = newStatus;
|
survey.curStatus = newStatus;
|
||||||
survey.statusList.push(newStatus);
|
survey.statusList.push(newStatus);
|
||||||
}
|
}
|
||||||
|
survey.updatedAt = new Date();
|
||||||
|
survey.operator = operator;
|
||||||
|
survey.operatorId = operatorId;
|
||||||
return this.surveyRepository.save(survey);
|
return this.surveyRepository.save(survey);
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteSurveyMeta(survey: SurveyMeta) {
|
async deleteSurveyMeta({ surveyId, operator, operatorId }) {
|
||||||
if (survey.curStatus.status === RECORD_STATUS.REMOVED) {
|
return this.surveyRepository.updateOne(
|
||||||
throw new HttpException(
|
{
|
||||||
'问卷已删除,不能重复删除',
|
_id: new ObjectId(surveyId),
|
||||||
EXCEPTION_CODE.SURVEY_STATUS_TRANSFORM_ERROR,
|
},
|
||||||
);
|
{
|
||||||
}
|
$set: {
|
||||||
const newStatusInfo = {
|
isDeleted: true,
|
||||||
status: RECORD_STATUS.REMOVED,
|
operator,
|
||||||
date: Date.now(),
|
operatorId,
|
||||||
};
|
deletedAt: new Date(),
|
||||||
survey.curStatus = newStatusInfo;
|
},
|
||||||
if (Array.isArray(survey.statusList)) {
|
},
|
||||||
survey.statusList.push(newStatusInfo);
|
);
|
||||||
} else {
|
|
||||||
survey.statusList = [newStatusInfo];
|
|
||||||
}
|
|
||||||
return this.surveyRepository.save(survey);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getSurveyMetaList(condition: {
|
async getSurveyMetaList(condition: {
|
||||||
@ -125,14 +150,16 @@ export class SurveyMetaService {
|
|||||||
const skip = (pageNum - 1) * pageSize;
|
const skip = (pageNum - 1) * pageSize;
|
||||||
try {
|
try {
|
||||||
const query: Record<string, any> = Object.assign(
|
const query: Record<string, any> = Object.assign(
|
||||||
{},
|
|
||||||
{
|
{
|
||||||
'curStatus.status': {
|
isDeleted: {
|
||||||
$ne: 'removed',
|
$ne: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
condition.filter,
|
condition.filter,
|
||||||
);
|
);
|
||||||
|
if (condition.filter['curStatus.status']) {
|
||||||
|
query['subStatus.status'] = RECORD_SUB_STATUS.DEFAULT;
|
||||||
|
}
|
||||||
if (workspaceId) {
|
if (workspaceId) {
|
||||||
query.workspaceId = workspaceId;
|
query.workspaceId = workspaceId;
|
||||||
} else {
|
} else {
|
||||||
@ -160,9 +187,8 @@ export class SurveyMetaService {
|
|||||||
condition.order && Object.keys(condition.order).length > 0
|
condition.order && Object.keys(condition.order).length > 0
|
||||||
? (condition.order as FindOptionsOrder<SurveyMeta>)
|
? (condition.order as FindOptionsOrder<SurveyMeta>)
|
||||||
: ({
|
: ({
|
||||||
createDate: -1,
|
createdAt: -1,
|
||||||
} as FindOptionsOrder<SurveyMeta>);
|
} as FindOptionsOrder<SurveyMeta>);
|
||||||
|
|
||||||
const [data, count] = await this.surveyRepository.findAndCount({
|
const [data, count] = await this.surveyRepository.findAndCount({
|
||||||
where: query,
|
where: query,
|
||||||
skip,
|
skip,
|
||||||
@ -181,6 +207,10 @@ export class SurveyMetaService {
|
|||||||
date: Date.now(),
|
date: Date.now(),
|
||||||
};
|
};
|
||||||
surveyMeta.curStatus = curStatus;
|
surveyMeta.curStatus = curStatus;
|
||||||
|
surveyMeta.subStatus = {
|
||||||
|
status: RECORD_SUB_STATUS.DEFAULT,
|
||||||
|
date: Date.now(),
|
||||||
|
};
|
||||||
if (Array.isArray(surveyMeta.statusList)) {
|
if (Array.isArray(surveyMeta.statusList)) {
|
||||||
surveyMeta.statusList.push(curStatus);
|
surveyMeta.statusList.push(curStatus);
|
||||||
} else {
|
} else {
|
||||||
@ -192,8 +222,8 @@ export class SurveyMetaService {
|
|||||||
async countSurveyMetaByWorkspaceId({ workspaceId }) {
|
async countSurveyMetaByWorkspaceId({ workspaceId }) {
|
||||||
const total = await this.surveyRepository.count({
|
const total = await this.surveyRepository.count({
|
||||||
workspaceId,
|
workspaceId,
|
||||||
'curStatus.status': {
|
isDeleted: {
|
||||||
$ne: RECORD_STATUS.REMOVED,
|
$ne: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
return total;
|
return total;
|
||||||
|
@ -25,11 +25,6 @@
|
|||||||
"msg_9003": "您来晚了,已经满额!",
|
"msg_9003": "您来晚了,已经满额!",
|
||||||
"msg_9004": "提交失败!"
|
"msg_9004": "提交失败!"
|
||||||
},
|
},
|
||||||
"jumpConfig": {
|
|
||||||
"type": "link",
|
|
||||||
"link": "",
|
|
||||||
"buttonText": ""
|
|
||||||
},
|
|
||||||
"link": ""
|
"link": ""
|
||||||
},
|
},
|
||||||
"bottomConf": {
|
"bottomConf": {
|
||||||
@ -37,7 +32,7 @@
|
|||||||
"logoImageWidth": "60%"
|
"logoImageWidth": "60%"
|
||||||
},
|
},
|
||||||
"baseConf": {
|
"baseConf": {
|
||||||
"begTime": "2024-01-01 00:00:00",
|
"beginTime": "2024-01-01 00:00:00",
|
||||||
"endTime": "2034-01-01 00:00:00",
|
"endTime": "2034-01-01 00:00:00",
|
||||||
"tLimit": 0,
|
"tLimit": 0,
|
||||||
"language": "chinese",
|
"language": "chinese",
|
||||||
|
@ -22,7 +22,7 @@ export async function getSchemaBySurveyType(surveyType: string) {
|
|||||||
}
|
}
|
||||||
const code = Object.assign({}, templateBase, codeData);
|
const code = Object.assign({}, templateBase, codeData);
|
||||||
const nowMoment = moment();
|
const nowMoment = moment();
|
||||||
code.baseConf.begTime = nowMoment.format('YYYY-MM-DD HH:mm:ss');
|
code.baseConf.beginTime = nowMoment.format('YYYY-MM-DD HH:mm:ss');
|
||||||
code.baseConf.endTime = nowMoment
|
code.baseConf.endTime = nowMoment
|
||||||
.add(10, 'years')
|
.add(10, 'years')
|
||||||
.format('YYYY-MM-DD HH:mm:ss');
|
.format('YYYY-MM-DD HH:mm:ss');
|
||||||
@ -63,7 +63,7 @@ export function getListHeadByDataList(dataList) {
|
|||||||
type: QUESTION_TYPE.TEXT,
|
type: QUESTION_TYPE.TEXT,
|
||||||
});
|
});
|
||||||
listHead.push({
|
listHead.push({
|
||||||
field: 'createDate',
|
field: 'createdAt',
|
||||||
title: '提交时间',
|
title: '提交时间',
|
||||||
type: QUESTION_TYPE.TEXT,
|
type: QUESTION_TYPE.TEXT,
|
||||||
});
|
});
|
||||||
|
@ -3,7 +3,6 @@ import { MongoRepository } from 'typeorm';
|
|||||||
import { ClientEncryptService } from '../services/clientEncrypt.service';
|
import { ClientEncryptService } from '../services/clientEncrypt.service';
|
||||||
import { ClientEncrypt } from 'src/models/clientEncrypt.entity';
|
import { ClientEncrypt } from 'src/models/clientEncrypt.entity';
|
||||||
import { ENCRYPT_TYPE } from 'src/enums/encrypt';
|
import { ENCRYPT_TYPE } from 'src/enums/encrypt';
|
||||||
import { RECORD_STATUS } from 'src/enums';
|
|
||||||
import { ObjectId } from 'mongodb';
|
import { ObjectId } from 'mongodb';
|
||||||
import { getRepositoryToken } from '@nestjs/typeorm';
|
import { getRepositoryToken } from '@nestjs/typeorm';
|
||||||
|
|
||||||
@ -88,9 +87,6 @@ describe('ClientEncryptService', () => {
|
|||||||
expect(repository.findOne).toHaveBeenCalledWith({
|
expect(repository.findOne).toHaveBeenCalledWith({
|
||||||
where: {
|
where: {
|
||||||
_id: new ObjectId(id),
|
_id: new ObjectId(id),
|
||||||
'curStatus.status': {
|
|
||||||
$ne: RECORD_STATUS.REMOVED,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
expect(result).toEqual(encryptInfo);
|
expect(result).toEqual(encryptInfo);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { ResponseSchema } from 'src/models/responseSchema.entity';
|
import { ResponseSchema } from 'src/models/responseSchema.entity';
|
||||||
import { RECORD_STATUS } from 'src/enums';
|
import { RECORD_STATUS, RECORD_SUB_STATUS } from 'src/enums';
|
||||||
import { ObjectId } from 'mongodb';
|
import { ObjectId } from 'mongodb';
|
||||||
|
|
||||||
export const mockResponseSchema: ResponseSchema = {
|
export const mockResponseSchema: ResponseSchema = {
|
||||||
@ -8,6 +8,10 @@ export const mockResponseSchema: ResponseSchema = {
|
|||||||
status: RECORD_STATUS.PUBLISHED,
|
status: RECORD_STATUS.PUBLISHED,
|
||||||
date: 1710399368439,
|
date: 1710399368439,
|
||||||
},
|
},
|
||||||
|
subStatus: {
|
||||||
|
status: RECORD_SUB_STATUS.DEFAULT,
|
||||||
|
date: 1710399368439,
|
||||||
|
},
|
||||||
statusList: [
|
statusList: [
|
||||||
{
|
{
|
||||||
status: RECORD_STATUS.PUBLISHED,
|
status: RECORD_STATUS.PUBLISHED,
|
||||||
@ -32,7 +36,7 @@ export const mockResponseSchema: ResponseSchema = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
baseConf: {
|
baseConf: {
|
||||||
begTime: '2024-03-14 14:54:41',
|
beginTime: '2024-03-14 14:54:41',
|
||||||
endTime: '2034-03-14 14:54:41',
|
endTime: '2034-03-14 14:54:41',
|
||||||
language: 'chinese',
|
language: 'chinese',
|
||||||
tLimit: 10,
|
tLimit: 10,
|
||||||
@ -252,4 +256,4 @@ export const mockResponseSchema: ResponseSchema = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
pageId: '65f29f3192862d6a9067ad1c',
|
pageId: '65f29f3192862d6a9067ad1c',
|
||||||
} as ResponseSchema;
|
} as unknown as ResponseSchema;
|
||||||
|
@ -3,7 +3,7 @@ import { ResponseSchemaController } from '../controllers/responseSchema.controll
|
|||||||
import { ResponseSchemaService } from '../services/responseScheme.service';
|
import { ResponseSchemaService } from '../services/responseScheme.service';
|
||||||
import { HttpException } from 'src/exceptions/httpException';
|
import { HttpException } from 'src/exceptions/httpException';
|
||||||
import { EXCEPTION_CODE } from 'src/enums/exceptionCode';
|
import { EXCEPTION_CODE } from 'src/enums/exceptionCode';
|
||||||
import { RECORD_STATUS } from 'src/enums';
|
import { RECORD_STATUS, RECORD_SUB_STATUS } from 'src/enums';
|
||||||
|
|
||||||
import { ResponseSchema } from 'src/models/responseSchema.entity';
|
import { ResponseSchema } from 'src/models/responseSchema.entity';
|
||||||
import { Logger } from 'src/logger';
|
import { Logger } from 'src/logger';
|
||||||
@ -69,6 +69,7 @@ describe('ResponseSchemaController', () => {
|
|||||||
const mockResponseSchema = {
|
const mockResponseSchema = {
|
||||||
surveyPath: 'testSurveyPath',
|
surveyPath: 'testSurveyPath',
|
||||||
curStatus: { status: RECORD_STATUS.PUBLISHED, date: Date.now() },
|
curStatus: { status: RECORD_STATUS.PUBLISHED, date: Date.now() },
|
||||||
|
subStatus: { status: RECORD_SUB_STATUS.DEFAULT, date: Date.now() },
|
||||||
} as ResponseSchema;
|
} as ResponseSchema;
|
||||||
|
|
||||||
jest
|
jest
|
||||||
@ -97,7 +98,7 @@ describe('ResponseSchemaController', () => {
|
|||||||
jest
|
jest
|
||||||
.spyOn(responseSchemaService, 'getResponseSchemaByPath')
|
.spyOn(responseSchemaService, 'getResponseSchemaByPath')
|
||||||
.mockResolvedValue({
|
.mockResolvedValue({
|
||||||
curStatus: { status: RECORD_STATUS.REMOVED },
|
subStatus: { status: RECORD_SUB_STATUS.REMOVED },
|
||||||
} as ResponseSchema);
|
} as ResponseSchema);
|
||||||
|
|
||||||
await expect(controller.getSchema(mockQueryInfo)).rejects.toThrow(
|
await expect(controller.getSchema(mockQueryInfo)).rejects.toThrow(
|
||||||
@ -125,6 +126,9 @@ describe('ResponseSchemaController', () => {
|
|||||||
curStatus: {
|
curStatus: {
|
||||||
status: 'published',
|
status: 'published',
|
||||||
},
|
},
|
||||||
|
subStatus: {
|
||||||
|
status: '',
|
||||||
|
},
|
||||||
code: {
|
code: {
|
||||||
baseConf: {
|
baseConf: {
|
||||||
passwordSwitch: true,
|
passwordSwitch: true,
|
||||||
@ -149,6 +153,9 @@ describe('ResponseSchemaController', () => {
|
|||||||
curStatus: {
|
curStatus: {
|
||||||
status: 'published',
|
status: 'published',
|
||||||
},
|
},
|
||||||
|
subStatus: {
|
||||||
|
status: '',
|
||||||
|
},
|
||||||
code: {
|
code: {
|
||||||
baseConf: {
|
baseConf: {
|
||||||
passwordSwitch: true,
|
passwordSwitch: true,
|
||||||
@ -172,6 +179,9 @@ describe('ResponseSchemaController', () => {
|
|||||||
curStatus: {
|
curStatus: {
|
||||||
status: 'published',
|
status: 'published',
|
||||||
},
|
},
|
||||||
|
subStatus: {
|
||||||
|
status: '',
|
||||||
|
},
|
||||||
code: {
|
code: {
|
||||||
baseConf: {
|
baseConf: {
|
||||||
passwordSwitch: true,
|
passwordSwitch: true,
|
||||||
@ -200,6 +210,9 @@ describe('ResponseSchemaController', () => {
|
|||||||
curStatus: {
|
curStatus: {
|
||||||
status: 'published',
|
status: 'published',
|
||||||
},
|
},
|
||||||
|
subStatus: {
|
||||||
|
status: '',
|
||||||
|
},
|
||||||
code: {
|
code: {
|
||||||
baseConf: {
|
baseConf: {
|
||||||
passwordSwitch: true,
|
passwordSwitch: true,
|
||||||
@ -228,6 +241,9 @@ describe('ResponseSchemaController', () => {
|
|||||||
curStatus: {
|
curStatus: {
|
||||||
status: 'published',
|
status: 'published',
|
||||||
},
|
},
|
||||||
|
subStatus: {
|
||||||
|
status: '',
|
||||||
|
},
|
||||||
code: {
|
code: {
|
||||||
baseConf: {
|
baseConf: {
|
||||||
passwordSwitch: true,
|
passwordSwitch: true,
|
||||||
|
@ -18,7 +18,7 @@ import { HttpException } from 'src/exceptions/httpException';
|
|||||||
import { SurveyNotFoundException } from 'src/exceptions/surveyNotFoundException';
|
import { SurveyNotFoundException } from 'src/exceptions/surveyNotFoundException';
|
||||||
import { ResponseSecurityPlugin } from 'src/securityPlugin/responseSecurityPlugin';
|
import { ResponseSecurityPlugin } from 'src/securityPlugin/responseSecurityPlugin';
|
||||||
|
|
||||||
import { RECORD_STATUS } from 'src/enums';
|
import { RECORD_STATUS, RECORD_SUB_STATUS } from 'src/enums';
|
||||||
import { SurveyResponse } from 'src/models/surveyResponse.entity';
|
import { SurveyResponse } from 'src/models/surveyResponse.entity';
|
||||||
import { Logger } from 'src/logger';
|
import { Logger } from 'src/logger';
|
||||||
import { ResponseSchema } from 'src/models/responseSchema.entity';
|
import { ResponseSchema } from 'src/models/responseSchema.entity';
|
||||||
@ -334,6 +334,9 @@ describe('SurveyResponseController', () => {
|
|||||||
curStatus: {
|
curStatus: {
|
||||||
status: RECORD_STATUS.PUBLISHED,
|
status: RECORD_STATUS.PUBLISHED,
|
||||||
},
|
},
|
||||||
|
subStatus: {
|
||||||
|
status: RECORD_SUB_STATUS.DEFAULT,
|
||||||
|
},
|
||||||
code: {
|
code: {
|
||||||
baseConf: {
|
baseConf: {
|
||||||
passwordSwitch: true,
|
passwordSwitch: true,
|
||||||
|
@ -77,7 +77,7 @@ describe('SurveyResponseService', () => {
|
|||||||
expect(surveyResponseRepository.count).toHaveBeenCalledWith({
|
expect(surveyResponseRepository.count).toHaveBeenCalledWith({
|
||||||
where: {
|
where: {
|
||||||
surveyPath,
|
surveyPath,
|
||||||
'curStatus.status': { $ne: 'removed' },
|
'subStatus.status': { $ne: 'removed' },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -10,7 +10,7 @@ import {
|
|||||||
import { ResponseSchemaService } from '../services/responseScheme.service';
|
import { ResponseSchemaService } from '../services/responseScheme.service';
|
||||||
import { HttpException } from 'src/exceptions/httpException';
|
import { HttpException } from 'src/exceptions/httpException';
|
||||||
import { EXCEPTION_CODE } from 'src/enums/exceptionCode';
|
import { EXCEPTION_CODE } from 'src/enums/exceptionCode';
|
||||||
import { RECORD_STATUS } from 'src/enums';
|
import { RECORD_SUB_STATUS } from 'src/enums';
|
||||||
import { ApiTags } from '@nestjs/swagger';
|
import { ApiTags } from '@nestjs/swagger';
|
||||||
import Joi from 'joi';
|
import Joi from 'joi';
|
||||||
import { Logger } from 'src/logger';
|
import { Logger } from 'src/logger';
|
||||||
@ -44,16 +44,20 @@ export class ResponseSchemaController {
|
|||||||
await this.responseSchemaService.getResponseSchemaByPath(
|
await this.responseSchemaService.getResponseSchemaByPath(
|
||||||
queryInfo.surveyPath,
|
queryInfo.surveyPath,
|
||||||
);
|
);
|
||||||
if (
|
if (!responseSchema || responseSchema.isDeleted) {
|
||||||
!responseSchema ||
|
|
||||||
responseSchema.curStatus.status === RECORD_STATUS.REMOVED
|
|
||||||
) {
|
|
||||||
throw new HttpException(
|
throw new HttpException(
|
||||||
'问卷已删除',
|
'问卷不存在或已删除',
|
||||||
EXCEPTION_CODE.RESPONSE_SCHEMA_REMOVED,
|
EXCEPTION_CODE.RESPONSE_SCHEMA_REMOVED,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (responseSchema.subStatus.status === RECORD_SUB_STATUS.PAUSING) {
|
||||||
|
throw new HttpException(
|
||||||
|
'该问卷已暂停回收',
|
||||||
|
EXCEPTION_CODE.RESPONSE_PAUSING,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// 去掉C端的敏感字段
|
// 去掉C端的敏感字段
|
||||||
if (responseSchema.code?.baseConf) {
|
if (responseSchema.code?.baseConf) {
|
||||||
responseSchema.code.baseConf.password = null;
|
responseSchema.code.baseConf.password = null;
|
||||||
@ -82,7 +86,7 @@ export class ResponseSchemaController {
|
|||||||
// 问卷信息
|
// 问卷信息
|
||||||
const schema =
|
const schema =
|
||||||
await this.responseSchemaService.getResponseSchemaByPath(surveyPath);
|
await this.responseSchemaService.getResponseSchemaByPath(surveyPath);
|
||||||
if (!schema || schema.curStatus.status === 'removed') {
|
if (!schema || schema.isDeleted) {
|
||||||
throw new SurveyNotFoundException('该问卷不存在,无法提交');
|
throw new SurveyNotFoundException('该问卷不存在,无法提交');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import { checkSign } from 'src/utils/checkSign';
|
|||||||
import { ENCRYPT_TYPE } from 'src/enums/encrypt';
|
import { ENCRYPT_TYPE } from 'src/enums/encrypt';
|
||||||
import { EXCEPTION_CODE } from 'src/enums/exceptionCode';
|
import { EXCEPTION_CODE } from 'src/enums/exceptionCode';
|
||||||
import { getPushingData } from 'src/utils/messagePushing';
|
import { getPushingData } from 'src/utils/messagePushing';
|
||||||
|
import { RECORD_SUB_STATUS } from 'src/enums';
|
||||||
|
|
||||||
import { ResponseSchemaService } from '../services/responseScheme.service';
|
import { ResponseSchemaService } from '../services/responseScheme.service';
|
||||||
import { SurveyResponseService } from '../services/surveyResponse.service';
|
import { SurveyResponseService } from '../services/surveyResponse.service';
|
||||||
@ -82,9 +83,15 @@ export class SurveyResponseController {
|
|||||||
// 查询schema
|
// 查询schema
|
||||||
const responseSchema =
|
const responseSchema =
|
||||||
await this.responseSchemaService.getResponseSchemaByPath(surveyPath);
|
await this.responseSchemaService.getResponseSchemaByPath(surveyPath);
|
||||||
if (!responseSchema || responseSchema.curStatus.status === 'removed') {
|
if (!responseSchema || responseSchema.isDeleted) {
|
||||||
throw new SurveyNotFoundException('该问卷不存在,无法提交');
|
throw new SurveyNotFoundException('该问卷不存在,无法提交');
|
||||||
}
|
}
|
||||||
|
if (responseSchema?.subStatus?.status === RECORD_SUB_STATUS.PAUSING) {
|
||||||
|
throw new HttpException(
|
||||||
|
'该问卷已暂停,无法提交',
|
||||||
|
EXCEPTION_CODE.RESPONSE_PAUSING,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// 白名单的verifyId校验
|
// 白名单的verifyId校验
|
||||||
const baseConf = responseSchema.code.baseConf;
|
const baseConf = responseSchema.code.baseConf;
|
||||||
@ -132,12 +139,12 @@ export class SurveyResponseController {
|
|||||||
|
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
// 提交时间限制
|
// 提交时间限制
|
||||||
const begTime = responseSchema.code?.baseConf?.begTime || 0;
|
const beginTime = responseSchema.code?.baseConf?.beginTime || 0;
|
||||||
const endTime = responseSchema?.code?.baseConf?.endTime || 0;
|
const endTime = responseSchema?.code?.baseConf?.endTime || 0;
|
||||||
if (begTime && endTime) {
|
if (beginTime && endTime) {
|
||||||
const begTimeStamp = new Date(begTime).getTime();
|
const beginTimeStamp = new Date(beginTime).getTime();
|
||||||
const endTimeStamp = new Date(endTime).getTime();
|
const endTimeStamp = new Date(endTime).getTime();
|
||||||
if (now < begTimeStamp || now > endTimeStamp) {
|
if (now < beginTimeStamp || now > endTimeStamp) {
|
||||||
throw new HttpException(
|
throw new HttpException(
|
||||||
'不在答题有效期内',
|
'不在答题有效期内',
|
||||||
EXCEPTION_CODE.RESPONSE_CURRENT_TIME_NOT_ALLOW,
|
EXCEPTION_CODE.RESPONSE_CURRENT_TIME_NOT_ALLOW,
|
||||||
|
@ -4,7 +4,6 @@ import { MongoRepository } from 'typeorm';
|
|||||||
import { ClientEncrypt } from 'src/models/clientEncrypt.entity';
|
import { ClientEncrypt } from 'src/models/clientEncrypt.entity';
|
||||||
import { ENCRYPT_TYPE } from 'src/enums/encrypt';
|
import { ENCRYPT_TYPE } from 'src/enums/encrypt';
|
||||||
import { ObjectId } from 'mongodb';
|
import { ObjectId } from 'mongodb';
|
||||||
import { RECORD_STATUS } from 'src/enums';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ClientEncryptService {
|
export class ClientEncryptService {
|
||||||
@ -38,26 +37,13 @@ export class ClientEncryptService {
|
|||||||
return this.clientEncryptRepository.findOne({
|
return this.clientEncryptRepository.findOne({
|
||||||
where: {
|
where: {
|
||||||
_id: new ObjectId(id),
|
_id: new ObjectId(id),
|
||||||
'curStatus.status': {
|
|
||||||
$ne: RECORD_STATUS.REMOVED,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteEncryptInfo(id: string) {
|
deleteEncryptInfo(id: string) {
|
||||||
return this.clientEncryptRepository.updateOne(
|
return this.clientEncryptRepository.deleteOne({
|
||||||
{
|
_id: new ObjectId(id),
|
||||||
_id: new ObjectId(id),
|
});
|
||||||
},
|
|
||||||
{
|
|
||||||
$set: {
|
|
||||||
curStatus: {
|
|
||||||
status: RECORD_STATUS.REMOVED,
|
|
||||||
date: Date.now(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@ export class CounterService {
|
|||||||
surveyPath,
|
surveyPath,
|
||||||
type,
|
type,
|
||||||
data,
|
data,
|
||||||
|
updatedAt: new Date(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common';
|
|||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
import { MongoRepository } from 'typeorm';
|
import { MongoRepository } from 'typeorm';
|
||||||
import { ResponseSchema } from 'src/models/responseSchema.entity';
|
import { ResponseSchema } from 'src/models/responseSchema.entity';
|
||||||
import { RECORD_STATUS } from 'src/enums';
|
import { RECORD_STATUS, RECORD_SUB_STATUS } from 'src/enums';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ResponseSchemaService {
|
export class ResponseSchemaService {
|
||||||
@ -23,19 +23,27 @@ export class ResponseSchemaService {
|
|||||||
status: RECORD_STATUS.PUBLISHED,
|
status: RECORD_STATUS.PUBLISHED,
|
||||||
date: Date.now(),
|
date: Date.now(),
|
||||||
};
|
};
|
||||||
|
clientSurvey.subStatus = {
|
||||||
|
status: RECORD_SUB_STATUS.DEFAULT,
|
||||||
|
date: Date.now(),
|
||||||
|
};
|
||||||
return this.responseSchemaRepository.save(clientSurvey);
|
return this.responseSchemaRepository.save(clientSurvey);
|
||||||
} else {
|
} else {
|
||||||
const curStatus = {
|
const curStatus = {
|
||||||
status: RECORD_STATUS.PUBLISHED,
|
status: RECORD_STATUS.PUBLISHED,
|
||||||
date: Date.now(),
|
date: Date.now(),
|
||||||
};
|
};
|
||||||
|
const subStatus = {
|
||||||
|
status: RECORD_SUB_STATUS.DEFAULT,
|
||||||
|
date: Date.now(),
|
||||||
|
};
|
||||||
const newClientSurvey = this.responseSchemaRepository.create({
|
const newClientSurvey = this.responseSchemaRepository.create({
|
||||||
title,
|
title,
|
||||||
surveyPath,
|
surveyPath,
|
||||||
code,
|
code,
|
||||||
pageId,
|
pageId,
|
||||||
curStatus,
|
curStatus,
|
||||||
statusList: [curStatus],
|
subStatus,
|
||||||
});
|
});
|
||||||
return this.responseSchemaRepository.save(newClientSurvey);
|
return this.responseSchemaRepository.save(newClientSurvey);
|
||||||
}
|
}
|
||||||
@ -53,22 +61,32 @@ export class ResponseSchemaService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteResponseSchema({ surveyPath }) {
|
async pausingResponseSchema({ surveyPath }) {
|
||||||
const responseSchema = await this.responseSchemaRepository.findOne({
|
const responseSchema = await this.responseSchemaRepository.findOne({
|
||||||
where: { surveyPath },
|
where: { surveyPath },
|
||||||
});
|
});
|
||||||
if (responseSchema) {
|
if (responseSchema) {
|
||||||
const newStatus = {
|
const subStatus = {
|
||||||
status: RECORD_STATUS.PUBLISHED,
|
status: RECORD_SUB_STATUS.PAUSING,
|
||||||
date: Date.now(),
|
date: Date.now(),
|
||||||
};
|
};
|
||||||
responseSchema.curStatus = newStatus;
|
responseSchema.subStatus = subStatus;
|
||||||
if (Array.isArray(responseSchema.statusList)) {
|
responseSchema.curStatus.status = RECORD_STATUS.PUBLISHED;
|
||||||
responseSchema.statusList.push(newStatus);
|
|
||||||
} else {
|
|
||||||
responseSchema.statusList = [newStatus];
|
|
||||||
}
|
|
||||||
return this.responseSchemaRepository.save(responseSchema);
|
return this.responseSchemaRepository.save(responseSchema);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async deleteResponseSchema({ surveyPath }) {
|
||||||
|
return this.responseSchemaRepository.updateOne(
|
||||||
|
{
|
||||||
|
surveyPath,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$set: {
|
||||||
|
isDeleted: true,
|
||||||
|
updatedAt: new Date(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common';
|
|||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
import { MongoRepository } from 'typeorm';
|
import { MongoRepository } from 'typeorm';
|
||||||
import { SurveyResponse } from 'src/models/surveyResponse.entity';
|
import { SurveyResponse } from 'src/models/surveyResponse.entity';
|
||||||
import { RECORD_STATUS } from 'src/enums';
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SurveyResponseService {
|
export class SurveyResponseService {
|
||||||
constructor(
|
constructor(
|
||||||
@ -39,9 +39,6 @@ export class SurveyResponseService {
|
|||||||
const data = await this.surveyResponseRepository.find({
|
const data = await this.surveyResponseRepository.find({
|
||||||
where: {
|
where: {
|
||||||
surveyPath,
|
surveyPath,
|
||||||
'curStatus.status': {
|
|
||||||
$ne: RECORD_STATUS.REMOVED,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
return (data || []).length;
|
return (data || []).length;
|
||||||
|
21
server/src/modules/upgrade/controllers/upgrade.controller.ts
Normal file
21
server/src/modules/upgrade/controllers/upgrade.controller.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { Controller, Get, HttpCode, Request } from '@nestjs/common';
|
||||||
|
import { ApiTags } from '@nestjs/swagger';
|
||||||
|
import { UpgradeService } from '../services/upgrade.service';
|
||||||
|
|
||||||
|
@ApiTags('survey')
|
||||||
|
@Controller('/api/upgrade')
|
||||||
|
export class UpgradeController {
|
||||||
|
constructor(private readonly upgradeService: UpgradeService) {}
|
||||||
|
|
||||||
|
@Get('/upgradeFeatureStatus')
|
||||||
|
@HttpCode(200)
|
||||||
|
async upgradeSubStatus(@Request() req) {
|
||||||
|
this.upgradeService.upgradeFeatureStatus();
|
||||||
|
return {
|
||||||
|
code: 200,
|
||||||
|
data: {
|
||||||
|
traceId: req.traceId,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
210
server/src/modules/upgrade/services/upgrade.service.ts
Normal file
210
server/src/modules/upgrade/services/upgrade.service.ts
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
|
import { MongoRepository } from 'typeorm';
|
||||||
|
import { SurveyMeta } from 'src/models/surveyMeta.entity';
|
||||||
|
import { ResponseSchema } from 'src/models/responseSchema.entity';
|
||||||
|
import { RECORD_STATUS, RECORD_SUB_STATUS } from 'src/enums';
|
||||||
|
import { Workspace } from 'src/models/workspace.entity';
|
||||||
|
import { Collaborator } from 'src/models/collaborator.entity';
|
||||||
|
import { Counter } from 'src/models/counter.entity';
|
||||||
|
import { DownloadTask } from 'src/models/downloadTask.entity';
|
||||||
|
import { MessagePushingLog } from 'src/models/messagePushingLog.entity';
|
||||||
|
import { MessagePushingTask } from 'src/models/messagePushingTask.entity';
|
||||||
|
import { Session } from 'src/models/session.entity';
|
||||||
|
import { SurveyConf } from 'src/models/surveyConf.entity';
|
||||||
|
import { User } from 'src/models/user.entity';
|
||||||
|
import { WorkspaceMember } from 'src/models/workspaceMember.entity';
|
||||||
|
import { SESSION_STATUS } from 'src/enums/surveySessionStatus';
|
||||||
|
import { Logger } from 'src/logger';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class UpgradeService {
|
||||||
|
constructor(
|
||||||
|
private readonly logger: Logger,
|
||||||
|
@InjectRepository(Collaborator)
|
||||||
|
private readonly collaboratorRepository: MongoRepository<Collaborator>,
|
||||||
|
@InjectRepository(Counter)
|
||||||
|
private readonly counterRepository: MongoRepository<Counter>,
|
||||||
|
@InjectRepository(DownloadTask)
|
||||||
|
private readonly downloadTaskRepository: MongoRepository<DownloadTask>,
|
||||||
|
@InjectRepository(MessagePushingLog)
|
||||||
|
private readonly messagePushingLogRepository: MongoRepository<MessagePushingLog>,
|
||||||
|
@InjectRepository(MessagePushingTask)
|
||||||
|
private readonly messagePushingTaskRepository: MongoRepository<MessagePushingTask>,
|
||||||
|
@InjectRepository(ResponseSchema)
|
||||||
|
private readonly responseSchemaRepository: MongoRepository<ResponseSchema>,
|
||||||
|
@InjectRepository(Session)
|
||||||
|
private readonly sessionRepository: MongoRepository<Session>,
|
||||||
|
@InjectRepository(SurveyConf)
|
||||||
|
private readonly surveyConfRepository: MongoRepository<SurveyConf>,
|
||||||
|
@InjectRepository(SurveyMeta)
|
||||||
|
private readonly surveyMetaRepository: MongoRepository<SurveyMeta>,
|
||||||
|
@InjectRepository(User)
|
||||||
|
private readonly userRepository: MongoRepository<User>,
|
||||||
|
@InjectRepository(Workspace)
|
||||||
|
private readonly workspaceRepository: MongoRepository<Workspace>,
|
||||||
|
@InjectRepository(WorkspaceMember)
|
||||||
|
private readonly workspaceMemberRepository: MongoRepository<WorkspaceMember>,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async upgradeFeatureStatus() {
|
||||||
|
const repositories = [
|
||||||
|
this.collaboratorRepository,
|
||||||
|
this.counterRepository,
|
||||||
|
this.downloadTaskRepository,
|
||||||
|
this.messagePushingLogRepository,
|
||||||
|
this.messagePushingTaskRepository,
|
||||||
|
this.responseSchemaRepository,
|
||||||
|
this.sessionRepository,
|
||||||
|
this.surveyConfRepository,
|
||||||
|
this.surveyMetaRepository,
|
||||||
|
this.userRepository,
|
||||||
|
this.workspaceRepository,
|
||||||
|
this.workspaceMemberRepository,
|
||||||
|
];
|
||||||
|
const handleCreatedAtAndUpdatedAt = (doc) => {
|
||||||
|
if (!doc.createdAt) {
|
||||||
|
if (doc.createDate) {
|
||||||
|
doc.createdAt = new Date(doc.createDate);
|
||||||
|
delete doc.createDate;
|
||||||
|
} else {
|
||||||
|
doc.createdAt = new Date();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!doc.updatedAt) {
|
||||||
|
if (doc.updateDate) {
|
||||||
|
doc.updatedAt = new Date(doc.updateDate);
|
||||||
|
delete doc.updateDate;
|
||||||
|
} else {
|
||||||
|
doc.updatedAt = new Date();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDelStatus = (doc) => {
|
||||||
|
// 已删除的字段升级
|
||||||
|
if (doc?.curStatus?.status === 'removed') {
|
||||||
|
delete doc.curStatus;
|
||||||
|
doc.isDeleted = true;
|
||||||
|
doc.deletedAt = new Date(doc.updatedAt);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubStatus = (doc) => {
|
||||||
|
// 编辑中字段升级
|
||||||
|
if (
|
||||||
|
!doc?.subStatus &&
|
||||||
|
(doc?.curStatus?.status == RECORD_STATUS.PUBLISHED ||
|
||||||
|
doc?.curStatus?.status == RECORD_STATUS.NEW ||
|
||||||
|
doc?.curStatus?.status === RECORD_STATUS.EDITING)
|
||||||
|
) {
|
||||||
|
const subStatus = {
|
||||||
|
status: RECORD_SUB_STATUS.DEFAULT,
|
||||||
|
date: doc.curStatus.date,
|
||||||
|
};
|
||||||
|
doc.subStatus = subStatus;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleBegTime = (doc) => {
|
||||||
|
if (!doc?.baseConf?.beginTime && doc?.baseConf?.begTime) {
|
||||||
|
doc.baseConf.beginTime = doc.baseConf.begTime;
|
||||||
|
delete doc.baseConf.begTime;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSessionStatus = (doc) => {
|
||||||
|
if (!doc.status && doc.curStatus) {
|
||||||
|
if (doc?.curStatus?.id && doc?.curStatus?.id === 'editing') {
|
||||||
|
doc.status = SESSION_STATUS.ACTIVATED;
|
||||||
|
} else {
|
||||||
|
doc.status = SESSION_STATUS.DEACTIVATED;
|
||||||
|
}
|
||||||
|
delete doc.curStatus;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCreatorId = async (doc) => {
|
||||||
|
if (!doc.ownerId && doc.owner) {
|
||||||
|
const userInfo = await this.userRepository.findOne({
|
||||||
|
where: {
|
||||||
|
username: doc.owner,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (userInfo && userInfo._id) {
|
||||||
|
doc.ownerId = userInfo._id.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (doc.ownerId && doc.owner && !doc.creatorId) {
|
||||||
|
doc.creatorId = doc.ownerId;
|
||||||
|
doc.creator = doc.owner;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const save = async ({ doc, repository }) => {
|
||||||
|
const entity = repository.create(doc);
|
||||||
|
await repository.updateOne(
|
||||||
|
{
|
||||||
|
_id: entity._id,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$set: entity,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
// this.logger.info(JSON.stringify(updateRes));
|
||||||
|
};
|
||||||
|
this.logger.info(`upgrading...`);
|
||||||
|
for (const repository of repositories) {
|
||||||
|
const name =
|
||||||
|
typeof repository.target === 'function'
|
||||||
|
? repository.target.name
|
||||||
|
: typeof repository.target === 'string'
|
||||||
|
? repository.target
|
||||||
|
: '';
|
||||||
|
|
||||||
|
const cursor = repository.createCursor();
|
||||||
|
this.logger.info(`upgrading ${name}`);
|
||||||
|
while (await cursor.hasNext()) {
|
||||||
|
try {
|
||||||
|
const doc = await cursor.next();
|
||||||
|
// 把createDate和updateDate升级成createdAt和updatedAt
|
||||||
|
handleCreatedAtAndUpdatedAt(doc);
|
||||||
|
if (
|
||||||
|
repository === this.surveyMetaRepository ||
|
||||||
|
repository === this.responseSchemaRepository
|
||||||
|
) {
|
||||||
|
// 新增subStatus字段
|
||||||
|
handleSubStatus(doc);
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
repository === this.surveyMetaRepository ||
|
||||||
|
repository === this.downloadTaskRepository ||
|
||||||
|
repository === this.messagePushingTaskRepository ||
|
||||||
|
repository === this.workspaceRepository ||
|
||||||
|
repository === this.responseSchemaRepository
|
||||||
|
) {
|
||||||
|
// 新增isDeleted等相关字段
|
||||||
|
handleDelStatus(doc);
|
||||||
|
}
|
||||||
|
// 同步sessionStatus到新定义的字段
|
||||||
|
if (repository === this.sessionRepository) {
|
||||||
|
handleSessionStatus(doc);
|
||||||
|
}
|
||||||
|
// 同步begTime,更新成beginTime
|
||||||
|
if (repository === this.surveyConfRepository) {
|
||||||
|
handleBegTime(doc);
|
||||||
|
}
|
||||||
|
// 同步ownerId到creatorId
|
||||||
|
if (repository === this.surveyMetaRepository) {
|
||||||
|
await handleCreatorId(doc);
|
||||||
|
}
|
||||||
|
await save({ repository, doc });
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.error(`upgrade ${name} error ${error.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.logger.info(`finish upgrade ${name}`);
|
||||||
|
}
|
||||||
|
this.logger.info(`upgrad finished...`);
|
||||||
|
}
|
||||||
|
}
|
51
server/src/modules/upgrade/upgrade.module.ts
Normal file
51
server/src/modules/upgrade/upgrade.module.ts
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
|
import { ConfigModule } from '@nestjs/config';
|
||||||
|
import { UpgradeService } from './services/upgrade.service';
|
||||||
|
|
||||||
|
import { Collaborator } from 'src/models/collaborator.entity';
|
||||||
|
import { Counter } from 'src/models/counter.entity';
|
||||||
|
import { DownloadTask } from 'src/models/downloadTask.entity';
|
||||||
|
import { MessagePushingLog } from 'src/models/messagePushingLog.entity';
|
||||||
|
import { MessagePushingTask } from 'src/models/messagePushingTask.entity';
|
||||||
|
import { ResponseSchema } from 'src/models/responseSchema.entity';
|
||||||
|
import { Session } from 'src/models/session.entity';
|
||||||
|
import { SurveyConf } from 'src/models/surveyConf.entity';
|
||||||
|
import { SurveyHistory } from 'src/models/surveyHistory.entity';
|
||||||
|
import { SurveyMeta } from 'src/models/surveyMeta.entity';
|
||||||
|
import { SurveyResponse } from 'src/models/surveyResponse.entity';
|
||||||
|
import { User } from 'src/models/user.entity';
|
||||||
|
import { Workspace } from 'src/models/workspace.entity';
|
||||||
|
import { WorkspaceMember } from 'src/models/workspaceMember.entity';
|
||||||
|
|
||||||
|
import { UpgradeController } from './controllers/upgrade.controller';
|
||||||
|
import { AuthModule } from '../auth/auth.module';
|
||||||
|
|
||||||
|
import { Logger } from 'src/logger';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [
|
||||||
|
TypeOrmModule.forFeature([
|
||||||
|
Collaborator,
|
||||||
|
Counter,
|
||||||
|
DownloadTask,
|
||||||
|
MessagePushingLog,
|
||||||
|
MessagePushingTask,
|
||||||
|
ResponseSchema,
|
||||||
|
Session,
|
||||||
|
SurveyConf,
|
||||||
|
SurveyHistory,
|
||||||
|
SurveyMeta,
|
||||||
|
SurveyResponse,
|
||||||
|
User,
|
||||||
|
Workspace,
|
||||||
|
WorkspaceMember,
|
||||||
|
]),
|
||||||
|
ConfigModule,
|
||||||
|
AuthModule,
|
||||||
|
],
|
||||||
|
controllers: [UpgradeController],
|
||||||
|
providers: [UpgradeService, Logger],
|
||||||
|
exports: [UpgradeService],
|
||||||
|
})
|
||||||
|
export class UpgradeModule {}
|
@ -242,11 +242,15 @@ describe('WorkspaceController', () => {
|
|||||||
|
|
||||||
describe('getWorkspaceAndMember', () => {
|
describe('getWorkspaceAndMember', () => {
|
||||||
it('should return a list of workspaces and members for the user', async () => {
|
it('should return a list of workspaces and members for the user', async () => {
|
||||||
const req = { user: { _id: new ObjectId() } };
|
|
||||||
|
|
||||||
const workspaceId = new ObjectId();
|
|
||||||
const userId = new ObjectId();
|
const userId = new ObjectId();
|
||||||
const memberList = [{ workspaceId, userId: userId }];
|
jest.spyOn(userService, 'getUserListByIds').mockResolvedValue([
|
||||||
|
{
|
||||||
|
_id: userId,
|
||||||
|
},
|
||||||
|
] as Array<User>);
|
||||||
|
const req = { user: { _id: userId } };
|
||||||
|
const workspaceId = new ObjectId();
|
||||||
|
const memberList = [{ workspaceId, userId }];
|
||||||
const workspaces = [{ _id: workspaceId, name: 'Test Workspace' }];
|
const workspaces = [{ _id: workspaceId, name: 'Test Workspace' }];
|
||||||
const userList = [{ _id: userId, username: 'Test User' }];
|
const userList = [{ _id: userId, username: 'Test User' }];
|
||||||
|
|
||||||
|
@ -100,10 +100,12 @@ export class WorkspaceController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const userId = req.user._id.toString();
|
const userId = req.user._id.toString();
|
||||||
|
const username = req.user.username;
|
||||||
// 插入空间表
|
// 插入空间表
|
||||||
const retWorkspace = await this.workspaceService.create({
|
const retWorkspace = await this.workspaceService.create({
|
||||||
name: value.name,
|
name: value.name,
|
||||||
description: value.description,
|
description: value.description,
|
||||||
|
owner: username,
|
||||||
ownerId: userId,
|
ownerId: userId,
|
||||||
});
|
});
|
||||||
const workspaceId = retWorkspace._id.toString();
|
const workspaceId = retWorkspace._id.toString();
|
||||||
@ -117,6 +119,8 @@ export class WorkspaceController {
|
|||||||
await this.workspaceMemberService.batchCreate({
|
await this.workspaceMemberService.batchCreate({
|
||||||
workspaceId,
|
workspaceId,
|
||||||
members: value.members,
|
members: value.members,
|
||||||
|
creator: username,
|
||||||
|
creatorId: userId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
@ -206,7 +210,7 @@ export class WorkspaceController {
|
|||||||
const ownerInfo = userInfoMap?.[item.ownerId] || {};
|
const ownerInfo = userInfoMap?.[item.ownerId] || {};
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
createDate: moment(item.createDate).format('YYYY-MM-DD HH:mm:ss'),
|
createdAt: moment(item.createdAt).format('YYYY-MM-DD HH:mm:ss'),
|
||||||
owner: ownerInfo.username,
|
owner: ownerInfo.username,
|
||||||
currentUserId: curWorkspaceInfo.userId,
|
currentUserId: curWorkspaceInfo.userId,
|
||||||
currentUserRole: curWorkspaceInfo.role,
|
currentUserRole: curWorkspaceInfo.role,
|
||||||
@ -268,13 +272,24 @@ export class WorkspaceController {
|
|||||||
@UseGuards(WorkspaceGuard)
|
@UseGuards(WorkspaceGuard)
|
||||||
@SetMetadata('workspacePermissions', [WORKSPACE_PERMISSION.WRITE_WORKSPACE])
|
@SetMetadata('workspacePermissions', [WORKSPACE_PERMISSION.WRITE_WORKSPACE])
|
||||||
@SetMetadata('workspaceId', 'params.id')
|
@SetMetadata('workspaceId', 'params.id')
|
||||||
async update(@Param('id') id: string, @Body() workspace: CreateWorkspaceDto) {
|
async update(
|
||||||
|
@Param('id') id: string,
|
||||||
|
@Body() workspace: CreateWorkspaceDto,
|
||||||
|
@Request() req,
|
||||||
|
) {
|
||||||
const members = workspace.members;
|
const members = workspace.members;
|
||||||
if (!Array.isArray(members) || members.length === 0) {
|
if (!Array.isArray(members) || members.length === 0) {
|
||||||
throw new HttpException('成员不能为空', EXCEPTION_CODE.PARAMETER_ERROR);
|
throw new HttpException('成员不能为空', EXCEPTION_CODE.PARAMETER_ERROR);
|
||||||
}
|
}
|
||||||
delete workspace.members;
|
delete workspace.members;
|
||||||
const updateRes = await this.workspaceService.update(id, workspace);
|
const operator = req.user.username,
|
||||||
|
operatorId = req.user._id.toString();
|
||||||
|
const updateRes = await this.workspaceService.update({
|
||||||
|
id,
|
||||||
|
workspace,
|
||||||
|
operator,
|
||||||
|
operatorId,
|
||||||
|
});
|
||||||
this.logger.info(`updateRes: ${JSON.stringify(updateRes)}`);
|
this.logger.info(`updateRes: ${JSON.stringify(updateRes)}`);
|
||||||
const { newMembers, adminMembers, userMembers } = splitMembers(members);
|
const { newMembers, adminMembers, userMembers } = splitMembers(members);
|
||||||
if (
|
if (
|
||||||
@ -320,14 +335,20 @@ export class WorkspaceController {
|
|||||||
this.workspaceMemberService.batchCreate({
|
this.workspaceMemberService.batchCreate({
|
||||||
workspaceId: id,
|
workspaceId: id,
|
||||||
members: newMembers,
|
members: newMembers,
|
||||||
|
creator: operator,
|
||||||
|
creatorId: operatorId,
|
||||||
}),
|
}),
|
||||||
this.workspaceMemberService.batchUpdate({
|
this.workspaceMemberService.batchUpdate({
|
||||||
idList: adminMembers,
|
idList: adminMembers,
|
||||||
role: WORKSPACE_ROLE.ADMIN,
|
role: WORKSPACE_ROLE.ADMIN,
|
||||||
|
operator,
|
||||||
|
operatorId,
|
||||||
}),
|
}),
|
||||||
this.workspaceMemberService.batchUpdate({
|
this.workspaceMemberService.batchUpdate({
|
||||||
idList: userMembers,
|
idList: userMembers,
|
||||||
role: WORKSPACE_ROLE.USER,
|
role: WORKSPACE_ROLE.USER,
|
||||||
|
operator,
|
||||||
|
operatorId,
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
this.logger.info(`updateRes: ${JSON.stringify(res)}`);
|
this.logger.info(`updateRes: ${JSON.stringify(res)}`);
|
||||||
@ -341,8 +362,13 @@ export class WorkspaceController {
|
|||||||
@UseGuards(WorkspaceGuard)
|
@UseGuards(WorkspaceGuard)
|
||||||
@SetMetadata('workspacePermissions', [WORKSPACE_PERMISSION.WRITE_WORKSPACE])
|
@SetMetadata('workspacePermissions', [WORKSPACE_PERMISSION.WRITE_WORKSPACE])
|
||||||
@SetMetadata('workspaceId', 'params.id')
|
@SetMetadata('workspaceId', 'params.id')
|
||||||
async delete(@Param('id') id: string) {
|
async delete(@Param('id') id: string, @Request() req) {
|
||||||
const res = await this.workspaceService.delete(id);
|
const operator = req.user.username,
|
||||||
|
operatorId = req.user._id.toString();
|
||||||
|
const res = await this.workspaceService.delete(id, {
|
||||||
|
operator,
|
||||||
|
operatorId,
|
||||||
|
});
|
||||||
this.logger.info(`res: ${JSON.stringify(res)}`);
|
this.logger.info(`res: ${JSON.stringify(res)}`);
|
||||||
return {
|
return {
|
||||||
code: 200,
|
code: 200,
|
||||||
|
@ -77,7 +77,10 @@ export class WorkspaceMemberController {
|
|||||||
@Post('updateRole')
|
@Post('updateRole')
|
||||||
@SetMetadata('workspacePermissions', [WORKSPACE_PERMISSION.WRITE_MEMBER])
|
@SetMetadata('workspacePermissions', [WORKSPACE_PERMISSION.WRITE_MEMBER])
|
||||||
@SetMetadata('workspaceId', 'body.workspaceId')
|
@SetMetadata('workspaceId', 'body.workspaceId')
|
||||||
async updateRole(@Body() updateDto: UpdateWorkspaceMemberDto) {
|
async updateRole(
|
||||||
|
@Body() updateDto: UpdateWorkspaceMemberDto,
|
||||||
|
@Request() req,
|
||||||
|
) {
|
||||||
const { error, value } = UpdateWorkspaceMemberDto.validate(updateDto);
|
const { error, value } = UpdateWorkspaceMemberDto.validate(updateDto);
|
||||||
if (error) {
|
if (error) {
|
||||||
throw new HttpException(
|
throw new HttpException(
|
||||||
@ -85,10 +88,14 @@ export class WorkspaceMemberController {
|
|||||||
EXCEPTION_CODE.PARAMETER_ERROR,
|
EXCEPTION_CODE.PARAMETER_ERROR,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
const operator = req.user.username,
|
||||||
|
operatorId = req.user._id.toString();
|
||||||
const updateRes = await this.workspaceMemberService.updateRole({
|
const updateRes = await this.workspaceMemberService.updateRole({
|
||||||
role: value.role,
|
role: value.role,
|
||||||
workspaceId: value.workspaceId,
|
workspaceId: value.workspaceId,
|
||||||
userId: value.userId,
|
userId: value.userId,
|
||||||
|
operator,
|
||||||
|
operatorId,
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
code: 200,
|
code: 200,
|
||||||
|
@ -6,7 +6,6 @@ import { Workspace } from 'src/models/workspace.entity';
|
|||||||
import { SurveyMeta } from 'src/models/surveyMeta.entity';
|
import { SurveyMeta } from 'src/models/surveyMeta.entity';
|
||||||
|
|
||||||
import { ObjectId } from 'mongodb';
|
import { ObjectId } from 'mongodb';
|
||||||
import { RECORD_STATUS } from 'src/enums';
|
|
||||||
|
|
||||||
interface FindAllByIdWithPaginationParams {
|
interface FindAllByIdWithPaginationParams {
|
||||||
workspaceIdList: string[];
|
workspaceIdList: string[];
|
||||||
@ -31,10 +30,13 @@ export class WorkspaceService {
|
|||||||
async create(workspace: {
|
async create(workspace: {
|
||||||
name: string;
|
name: string;
|
||||||
description: string;
|
description: string;
|
||||||
|
owner: string;
|
||||||
ownerId: string;
|
ownerId: string;
|
||||||
}): Promise<Workspace> {
|
}): Promise<Workspace> {
|
||||||
const newWorkspace = this.workspaceRepository.create({
|
const newWorkspace = this.workspaceRepository.create({
|
||||||
...workspace,
|
...workspace,
|
||||||
|
creatorId: workspace.ownerId,
|
||||||
|
creator: workspace.owner,
|
||||||
});
|
});
|
||||||
return this.workspaceRepository.save(newWorkspace);
|
return this.workspaceRepository.save(newWorkspace);
|
||||||
}
|
}
|
||||||
@ -56,8 +58,8 @@ export class WorkspaceService {
|
|||||||
_id: {
|
_id: {
|
||||||
$in: workspaceIdList.map((item) => new ObjectId(item)),
|
$in: workspaceIdList.map((item) => new ObjectId(item)),
|
||||||
},
|
},
|
||||||
'curStatus.status': {
|
isDeleted: {
|
||||||
$ne: RECORD_STATUS.REMOVED,
|
$ne: true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -68,11 +70,11 @@ export class WorkspaceService {
|
|||||||
},
|
},
|
||||||
select: [
|
select: [
|
||||||
'_id',
|
'_id',
|
||||||
'curStatus',
|
|
||||||
'name',
|
'name',
|
||||||
'description',
|
'description',
|
||||||
'ownerId',
|
'ownerId',
|
||||||
'createDate',
|
'creatorId',
|
||||||
|
'createdAt',
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -91,8 +93,8 @@ export class WorkspaceService {
|
|||||||
_id: {
|
_id: {
|
||||||
$in: workspaceIdList.map((m) => new ObjectId(m)),
|
$in: workspaceIdList.map((m) => new ObjectId(m)),
|
||||||
},
|
},
|
||||||
'curStatus.status': {
|
isDeleted: {
|
||||||
$ne: RECORD_STATUS.REMOVED,
|
$ne: true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
if (name) {
|
if (name) {
|
||||||
@ -103,31 +105,40 @@ export class WorkspaceService {
|
|||||||
skip,
|
skip,
|
||||||
take: limit,
|
take: limit,
|
||||||
order: {
|
order: {
|
||||||
createDate: -1,
|
createdAt: -1,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
return { list: data, count };
|
return { list: data, count };
|
||||||
}
|
}
|
||||||
|
|
||||||
update(id: string, workspace: Partial<Workspace>) {
|
update({
|
||||||
|
id,
|
||||||
|
workspace,
|
||||||
|
operator,
|
||||||
|
operatorId,
|
||||||
|
}: {
|
||||||
|
id: string;
|
||||||
|
workspace: Partial<Workspace>;
|
||||||
|
operator: string;
|
||||||
|
operatorId: string;
|
||||||
|
}) {
|
||||||
|
workspace.updatedAt = new Date();
|
||||||
|
workspace.operator = operator;
|
||||||
|
workspace.operatorId = operatorId;
|
||||||
return this.workspaceRepository.update(id, workspace);
|
return this.workspaceRepository.update(id, workspace);
|
||||||
}
|
}
|
||||||
|
|
||||||
async delete(id: string) {
|
async delete(id: string, { operator, operatorId }) {
|
||||||
const newStatus = {
|
|
||||||
status: RECORD_STATUS.REMOVED,
|
|
||||||
date: Date.now(),
|
|
||||||
};
|
|
||||||
const workspaceRes = await this.workspaceRepository.updateOne(
|
const workspaceRes = await this.workspaceRepository.updateOne(
|
||||||
{
|
{
|
||||||
_id: new ObjectId(id),
|
_id: new ObjectId(id),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
$set: {
|
$set: {
|
||||||
curStatus: newStatus,
|
isDeleted: true,
|
||||||
},
|
deletedAt: new Date(),
|
||||||
$push: {
|
operator,
|
||||||
statusList: newStatus as never,
|
operatorId,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -137,10 +148,10 @@ export class WorkspaceService {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
$set: {
|
$set: {
|
||||||
curStatus: newStatus,
|
isDeleted: true,
|
||||||
},
|
deletedAt: new Date(),
|
||||||
$push: {
|
operator,
|
||||||
statusList: newStatus as never,
|
operatorId,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -155,8 +166,8 @@ export class WorkspaceService {
|
|||||||
return await this.workspaceRepository.find({
|
return await this.workspaceRepository.find({
|
||||||
where: {
|
where: {
|
||||||
ownerId: userId,
|
ownerId: userId,
|
||||||
'curStatus.status': {
|
isDeleted: {
|
||||||
$ne: RECORD_STATUS.REMOVED,
|
$ne: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
order: {
|
order: {
|
||||||
@ -168,7 +179,7 @@ export class WorkspaceService {
|
|||||||
'name',
|
'name',
|
||||||
'description',
|
'description',
|
||||||
'ownerId',
|
'ownerId',
|
||||||
'createDate',
|
'createdAt',
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ import { InjectRepository } from '@nestjs/typeorm';
|
|||||||
import { MongoRepository } from 'typeorm';
|
import { MongoRepository } from 'typeorm';
|
||||||
import { WorkspaceMember } from 'src/models/workspaceMember.entity';
|
import { WorkspaceMember } from 'src/models/workspaceMember.entity';
|
||||||
import { ObjectId } from 'mongodb';
|
import { ObjectId } from 'mongodb';
|
||||||
import { RECORD_STATUS } from 'src/enums';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class WorkspaceMemberService {
|
export class WorkspaceMemberService {
|
||||||
@ -24,25 +23,44 @@ export class WorkspaceMemberService {
|
|||||||
async batchCreate({
|
async batchCreate({
|
||||||
workspaceId,
|
workspaceId,
|
||||||
members,
|
members,
|
||||||
|
creator,
|
||||||
|
creatorId,
|
||||||
}: {
|
}: {
|
||||||
workspaceId: string;
|
workspaceId: string;
|
||||||
members: Array<{ userId: string; role: string }>;
|
members: Array<{ userId: string; role: string }>;
|
||||||
|
creator: string;
|
||||||
|
creatorId: string;
|
||||||
}) {
|
}) {
|
||||||
if (members.length === 0) {
|
if (members.length === 0) {
|
||||||
return {
|
return {
|
||||||
insertedCount: 0,
|
insertedCount: 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
const now = new Date();
|
||||||
const dataToInsert = members.map((item) => {
|
const dataToInsert = members.map((item) => {
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
|
createdAt: now,
|
||||||
|
updatedAt: now,
|
||||||
|
creator,
|
||||||
|
creatorId,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
return this.workspaceMemberRepository.insertMany(dataToInsert);
|
return this.workspaceMemberRepository.insertMany(dataToInsert);
|
||||||
}
|
}
|
||||||
|
|
||||||
async batchUpdate({ idList, role }: { idList: Array<string>; role: string }) {
|
async batchUpdate({
|
||||||
|
idList,
|
||||||
|
role,
|
||||||
|
operator,
|
||||||
|
operatorId,
|
||||||
|
}: {
|
||||||
|
idList: Array<string>;
|
||||||
|
role: string;
|
||||||
|
operator: string;
|
||||||
|
operatorId: string;
|
||||||
|
}) {
|
||||||
if (idList.length === 0) {
|
if (idList.length === 0) {
|
||||||
return {
|
return {
|
||||||
modifiedCount: 0,
|
modifiedCount: 0,
|
||||||
@ -57,6 +75,9 @@ export class WorkspaceMemberService {
|
|||||||
{
|
{
|
||||||
$set: {
|
$set: {
|
||||||
role,
|
role,
|
||||||
|
operator,
|
||||||
|
operatorId,
|
||||||
|
updatedAt: new Date(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -94,11 +115,8 @@ export class WorkspaceMemberService {
|
|||||||
return this.workspaceMemberRepository.find({
|
return this.workspaceMemberRepository.find({
|
||||||
where: {
|
where: {
|
||||||
workspaceId,
|
workspaceId,
|
||||||
'curStatus.status': {
|
|
||||||
$ne: RECORD_STATUS.REMOVED,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
select: ['_id', 'createDate', 'curStatus', 'role', 'userId'],
|
select: ['_id', 'createdAt', 'curStatus', 'role', 'userId'],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,7 +129,7 @@ export class WorkspaceMemberService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateRole({ workspaceId, userId, role }) {
|
async updateRole({ workspaceId, userId, role, operator, operatorId }) {
|
||||||
return this.workspaceMemberRepository.updateOne(
|
return this.workspaceMemberRepository.updateOne(
|
||||||
{
|
{
|
||||||
workspaceId,
|
workspaceId,
|
||||||
@ -120,6 +138,9 @@ export class WorkspaceMemberService {
|
|||||||
{
|
{
|
||||||
$set: {
|
$set: {
|
||||||
role,
|
role,
|
||||||
|
operator,
|
||||||
|
operatorId,
|
||||||
|
updatedAt: new Date(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -135,9 +156,6 @@ export class WorkspaceMemberService {
|
|||||||
async countByWorkspaceId({ workspaceId }) {
|
async countByWorkspaceId({ workspaceId }) {
|
||||||
return this.workspaceMemberRepository.count({
|
return this.workspaceMemberRepository.count({
|
||||||
workspaceId,
|
workspaceId,
|
||||||
'curStatus.status': {
|
|
||||||
$ne: RECORD_STATUS.REMOVED,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ export function getFilter(filterList: Array<FilterItem>) {
|
|||||||
'remark',
|
'remark',
|
||||||
'surveyType',
|
'surveyType',
|
||||||
'curStatus.status',
|
'curStatus.status',
|
||||||
|
'subStatus.status',
|
||||||
];
|
];
|
||||||
return filterList.reduce(
|
return filterList.reduce(
|
||||||
(preItem, curItem) => {
|
(preItem, curItem) => {
|
||||||
@ -61,7 +62,7 @@ export function getFilter(filterList: Array<FilterItem>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getOrder(order: Array<OrderItem>) {
|
export function getOrder(order: Array<OrderItem>) {
|
||||||
const allowOrderFields = ['createDate', 'updateDate', 'curStatus.date'];
|
const allowOrderFields = ['createdAt', 'updatedAt', 'curStatus.date'];
|
||||||
|
|
||||||
const orderList = order.filter((orderItem) =>
|
const orderList = order.filter((orderItem) =>
|
||||||
allowOrderFields.includes(orderItem.field),
|
allowOrderFields.includes(orderItem.field),
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "web",
|
"name": "xiaoju-survey-web",
|
||||||
"version": "0.1.0",
|
"version": "1.3.0",
|
||||||
"private": true,
|
"description": "XIAOJUSURVEY的web端,包含B端和C端应用",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"serve": "npm run dev",
|
"serve": "npm run dev",
|
||||||
@ -41,6 +41,7 @@
|
|||||||
"@iconify-json/ep": "^1.1.15",
|
"@iconify-json/ep": "^1.1.15",
|
||||||
"@rushstack/eslint-patch": "^1.10.2",
|
"@rushstack/eslint-patch": "^1.10.2",
|
||||||
"@tsconfig/node20": "^20.1.2",
|
"@tsconfig/node20": "^20.1.2",
|
||||||
|
"@types/fs-extra": "^11.0.4",
|
||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/node": "^20.11.19",
|
"@types/node": "^20.11.19",
|
||||||
"@types/qrcode": "^1.5.5",
|
"@types/qrcode": "^1.5.5",
|
||||||
@ -52,6 +53,7 @@
|
|||||||
"@vue/tsconfig": "^0.5.1",
|
"@vue/tsconfig": "^0.5.1",
|
||||||
"eslint": "^8.49.0",
|
"eslint": "^8.49.0",
|
||||||
"eslint-plugin-vue": "^9.17.0",
|
"eslint-plugin-vue": "^9.17.0",
|
||||||
|
"fs-extra": "^11.2.0",
|
||||||
"husky": "^9.0.11",
|
"husky": "^9.0.11",
|
||||||
"npm-run-all2": "^6.1.1",
|
"npm-run-all2": "^6.1.1",
|
||||||
"prettier": "^3.0.3",
|
"prettier": "^3.0.3",
|
||||||
|
47
web/report.ts
Normal file
47
web/report.ts
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import fs from 'fs-extra'
|
||||||
|
|
||||||
|
const fsa = fs.promises
|
||||||
|
|
||||||
|
process.env.XIAOJU_SURVEY_REPORT = 'true'
|
||||||
|
|
||||||
|
const readData = async (pkg: string) => {
|
||||||
|
const id = new Date().getTime().toString()
|
||||||
|
try {
|
||||||
|
if (!fs.existsSync(pkg)) {
|
||||||
|
return {
|
||||||
|
type: 'web',
|
||||||
|
name: '',
|
||||||
|
version: '',
|
||||||
|
description: '',
|
||||||
|
id,
|
||||||
|
msg: '文件不存在'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const data = await fsa.readFile(pkg, 'utf8').catch((e) => e)
|
||||||
|
const { name, version, description } = JSON.parse(data)
|
||||||
|
return { type: 'web', name, version, description, id }
|
||||||
|
} catch (error) {
|
||||||
|
return error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const report = async () => {
|
||||||
|
if (!process.env.XIAOJU_SURVEY_REPORT) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await readData('./package.json')
|
||||||
|
|
||||||
|
// 上报
|
||||||
|
fetch &&
|
||||||
|
fetch('https://xiaojusurveysrc.didi.cn/reportSourceData', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
Accept: 'application/json, */*',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify(res)
|
||||||
|
}).catch(() => {})
|
||||||
|
}
|
||||||
|
|
||||||
|
report()
|
@ -16,3 +16,4 @@ export const getStatisticList = (data) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ export const createSurvey = (data) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const getSurveyHistory = ({ surveyId, historyType }) => {
|
export const getSurveyHistory = ({ surveyId, historyType }) => {
|
||||||
return axios.get('/surveyHisotry/getList', {
|
return axios.get('/surveyHistory/getList', {
|
||||||
params: {
|
params: {
|
||||||
surveyId,
|
surveyId,
|
||||||
historyType
|
historyType
|
||||||
@ -53,6 +53,16 @@ export const updateSurvey = (data) => {
|
|||||||
return axios.post('/survey/updateMeta', data)
|
return axios.post('/survey/updateMeta', data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const pausingSurvey= (surveyId) => {
|
||||||
|
return axios.post('/survey/pausingSurvey', {
|
||||||
|
surveyId
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const upgradeSubStatus = () => {
|
||||||
|
return axios.get('/upgrade/subStatus')
|
||||||
|
}
|
||||||
|
|
||||||
export const getSessionId = ({ surveyId }) => {
|
export const getSessionId = ({ surveyId }) => {
|
||||||
return axios.post('/session/create', { surveyId })
|
return axios.post('/session/create', { surveyId })
|
||||||
}
|
}
|
||||||
|
@ -27,9 +27,9 @@ export const spaceListConfig = {
|
|||||||
key: 'owner',
|
key: 'owner',
|
||||||
width: 150
|
width: 150
|
||||||
},
|
},
|
||||||
createDate: {
|
createdAt: {
|
||||||
title: '创建时间',
|
title: '创建时间',
|
||||||
key: 'createDate',
|
key: 'createdAt',
|
||||||
minWidth: 200
|
minWidth: 200
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -64,14 +64,14 @@ export const fieldConfig = {
|
|||||||
key: 'owner',
|
key: 'owner',
|
||||||
width: 140
|
width: 140
|
||||||
},
|
},
|
||||||
updateDate: {
|
updatedAt: {
|
||||||
title: '更新时间',
|
title: '更新时间',
|
||||||
key: 'curStatus.date',
|
key: 'updatedAt',
|
||||||
minWidth: 200
|
minWidth: 200
|
||||||
},
|
},
|
||||||
createDate: {
|
createdAt: {
|
||||||
title: '创建时间',
|
title: '创建时间',
|
||||||
key: 'createDate',
|
key: 'createdAt',
|
||||||
minWidth: 200
|
minWidth: 200
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -103,14 +103,37 @@ export const noDownloadTaskConfig = {
|
|||||||
img: '/imgs/icons/list-empty.webp'
|
img: '/imgs/icons/list-empty.webp'
|
||||||
}
|
}
|
||||||
|
|
||||||
export const statusMaps = {
|
export const curStatus = {
|
||||||
new: '未发布',
|
new: {
|
||||||
editing: '修改中',
|
value: 'new',
|
||||||
published: '已发布',
|
label: '未发布'
|
||||||
removed: '已删除',
|
},
|
||||||
pausing: ''
|
published: {
|
||||||
|
value: 'published',
|
||||||
|
label: '已发布'
|
||||||
|
},
|
||||||
|
editing: {
|
||||||
|
label: '修改中',
|
||||||
|
value: 'editing'
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 子状态
|
||||||
|
export const subStatus = {
|
||||||
|
pausing: {
|
||||||
|
label: '暂停中',
|
||||||
|
value: 'pausing'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const statusMaps = {
|
||||||
|
...Object.fromEntries(Object.keys(curStatus).map(key => ([key, curStatus[key].label]))),
|
||||||
|
...Object.fromEntries(Object.keys(subStatus).map(key => ([key, subStatus[key].label])))
|
||||||
|
}
|
||||||
|
|
||||||
|
export const curStatusKey = 'curStatus.status';
|
||||||
|
export const subStatusKey = 'subStatus.status';
|
||||||
|
|
||||||
// 问卷类型
|
// 问卷类型
|
||||||
export const surveyTypeSelect = {
|
export const surveyTypeSelect = {
|
||||||
label: '问卷类型',
|
label: '问卷类型',
|
||||||
@ -151,29 +174,21 @@ export const curStatusSelect = {
|
|||||||
value: '',
|
value: '',
|
||||||
label: '全部状态'
|
label: '全部状态'
|
||||||
},
|
},
|
||||||
{
|
curStatus.new,
|
||||||
value: 'new',
|
curStatus.published,
|
||||||
label: '未发布'
|
curStatus.editing,
|
||||||
},
|
subStatus.pausing
|
||||||
{
|
|
||||||
value: 'published',
|
|
||||||
label: '已发布'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'editing',
|
|
||||||
label: '修改中'
|
|
||||||
}
|
|
||||||
],
|
],
|
||||||
default: ''
|
default: ''
|
||||||
}
|
}
|
||||||
|
|
||||||
export const selectOptionsDict = Object.freeze({
|
export const selectOptionsDict = Object.freeze({
|
||||||
surveyType: surveyTypeSelect,
|
surveyType: surveyTypeSelect,
|
||||||
'curStatus.status': curStatusSelect
|
status: curStatusSelect,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const buttonOptionsDict = Object.freeze({
|
export const buttonOptionsDict = Object.freeze({
|
||||||
'curStatus.date': {
|
'updatedAt': {
|
||||||
label: '更新时间',
|
label: '更新时间',
|
||||||
icons: [
|
icons: [
|
||||||
{
|
{
|
||||||
@ -194,7 +209,7 @@ export const buttonOptionsDict = Object.freeze({
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
createDate: {
|
createdAt: {
|
||||||
label: '创建时间',
|
label: '创建时间',
|
||||||
icons: [
|
icons: [
|
||||||
{
|
{
|
||||||
|
@ -80,7 +80,7 @@ const popoverContent = ref('')
|
|||||||
|
|
||||||
const getContent = (content) => {
|
const getContent = (content) => {
|
||||||
if (Array.isArray(content)) {
|
if (Array.isArray(content)) {
|
||||||
return content.map((item) => getContent(item)).join(',')
|
return content.map(item => getContent(item)).join(',');
|
||||||
}
|
}
|
||||||
if (content === null || content === undefined) {
|
if (content === null || content === undefined) {
|
||||||
return ''
|
return ''
|
||||||
|
@ -194,7 +194,7 @@ const checkIsTaskFinished = (taskId) => {
|
|||||||
const run = () => {
|
const run = () => {
|
||||||
getDownloadTask(taskId).then((res) => {
|
getDownloadTask(taskId).then((res) => {
|
||||||
if (res.code === 200 && res.data) {
|
if (res.code === 200 && res.data) {
|
||||||
const status = res.data.curStatus.status
|
const status = res.data.status
|
||||||
if (status === 'new' || status === 'computing') {
|
if (status === 'new' || status === 'computing') {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
run()
|
run()
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
<el-table-column label="操作" width="200">
|
<el-table-column label="操作" width="200">
|
||||||
<template v-slot="{ row }">
|
<template v-slot="{ row }">
|
||||||
<span
|
<span
|
||||||
v-if="row.curStatus?.status === 'finished'"
|
v-if="row?.status === 'succeed'"
|
||||||
class="text-btn download-btn"
|
class="text-btn download-btn"
|
||||||
@click="handleDownload(row)"
|
@click="handleDownload(row)"
|
||||||
>
|
>
|
||||||
@ -90,21 +90,19 @@ const getList = async ({ pageIndex }: { pageIndex: number }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const statusTextMap: Record<string, string> = {
|
const statusTextMap: Record<string, string> = {
|
||||||
new: '排队中',
|
waiting: '排队中',
|
||||||
computing: '计算中',
|
computing: '计算中',
|
||||||
finished: '已完成',
|
succeed: '已完成',
|
||||||
removed: '已删除'
|
failed: '导出失败',
|
||||||
}
|
}
|
||||||
|
|
||||||
let currentDelRow: Record<string, any> = {}
|
let currentDelRow: Record<string, any> = {}
|
||||||
// 下载文件
|
// 下载文件
|
||||||
const handleDownload = async (row: any) => {
|
const handleDownload = async (row: any) => {
|
||||||
if (row.curStatus.status === 'removed') {
|
|
||||||
ElMessage.error('文件已删除')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (row.url) {
|
if (row.url) {
|
||||||
window.open(row.url)
|
window.open(row.url)
|
||||||
|
} else {
|
||||||
|
ElMessageBox.alert('文件不存在')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 删除文件
|
// 删除文件
|
||||||
@ -137,7 +135,7 @@ const confirmDelete = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const fields = ['filename', 'fileSize', 'createDate', 'curStatus']
|
const fields = ['filename', 'fileSize', 'createdAt', 'status']
|
||||||
|
|
||||||
const fieldList = computed(() => {
|
const fieldList = computed(() => {
|
||||||
return map(fields, (f) => {
|
return map(fields, (f) => {
|
||||||
@ -157,14 +155,14 @@ const downloadListConfig = {
|
|||||||
key: 'fileSize',
|
key: 'fileSize',
|
||||||
width: 140
|
width: 140
|
||||||
},
|
},
|
||||||
createDate: {
|
createdAt: {
|
||||||
title: '下载时间',
|
title: '下载时间',
|
||||||
key: 'createDate',
|
key: 'createdAt',
|
||||||
width: 240
|
width: 240
|
||||||
},
|
},
|
||||||
curStatus: {
|
status: {
|
||||||
title: '状态',
|
title: '状态',
|
||||||
key: 'curStatus.status',
|
key: 'status',
|
||||||
formatter(row: Record<string, any>, column: Record<string, any>) {
|
formatter(row: Record<string, any>, column: Record<string, any>) {
|
||||||
return statusTextMap[get(row, column.rawColumnKey)]
|
return statusTextMap[get(row, column.rawColumnKey)]
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ import LeftMenu from '@/management/components/LeftMenu.vue'
|
|||||||
import CommonTemplate from './components/CommonTemplate.vue'
|
import CommonTemplate from './components/CommonTemplate.vue'
|
||||||
import Navbar from './components/ModuleNavbar.vue'
|
import Navbar from './components/ModuleNavbar.vue'
|
||||||
|
|
||||||
|
|
||||||
const editStore = useEditStore()
|
const editStore = useEditStore()
|
||||||
const { init, setSurveyId, schema } = editStore
|
const { init, setSurveyId, schema } = editStore
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ import { getSurveyHistory } from '@/management/api/survey'
|
|||||||
|
|
||||||
const getItemData = (item: any) => ({
|
const getItemData = (item: any) => ({
|
||||||
operator: item?.operator?.username || '未知用户',
|
operator: item?.operator?.username || '未知用户',
|
||||||
time: moment(item.createDate).format('YYYY-MM-DD HH:mm:ss')
|
time: moment(item.createdAt).format('YYYY-MM-DD HH:mm:ss')
|
||||||
})
|
})
|
||||||
|
|
||||||
const dailyList = ref<Array<any>>([])
|
const dailyList = ref<Array<any>>([])
|
||||||
|
@ -57,7 +57,6 @@ const onSave = async () => {
|
|||||||
ElMessage.error('未获取到sessionId')
|
ElMessage.error('未获取到sessionId')
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!saveData.value.surveyId) {
|
if (!saveData.value.surveyId) {
|
||||||
ElMessage.error('未获取到问卷id')
|
ElMessage.error('未获取到问卷id')
|
||||||
return null
|
return null
|
||||||
|
@ -81,7 +81,6 @@ const onSave = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const res: Record<string, any> = await saveSurvey(saveData)
|
const res: Record<string, any> = await saveSurvey(saveData)
|
||||||
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// 问卷设置,定义了字段和对应的设置器
|
// 问卷设置,定义了字段和对应的设置器
|
||||||
export default {
|
export default {
|
||||||
base_effectTime: {
|
base_effectTime: {
|
||||||
keys: ['begTime', 'endTime'],
|
keys: ['beginTime', 'endTime'],
|
||||||
label: '答题有效期',
|
label: '答题有效期',
|
||||||
type: 'QuestionTime',
|
type: 'QuestionTime',
|
||||||
placeholder: 'yyyy-MM-dd hh:mm:ss'
|
placeholder: 'yyyy-MM-dd hh:mm:ss'
|
||||||
@ -114,5 +114,5 @@ export default {
|
|||||||
relyFunc: (data) => {
|
relyFunc: (data) => {
|
||||||
return data.whitelistType == 'MEMBER'
|
return data.whitelistType == 'MEMBER'
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
@row-click="onRowClick"
|
@row-click="onRowClick"
|
||||||
>
|
>
|
||||||
<el-table-column column-key="space" width="20" />
|
<el-table-column column-key="space" width="20" />
|
||||||
|
|
||||||
<el-table-column
|
<el-table-column
|
||||||
v-for="field in fieldList"
|
v-for="field in fieldList"
|
||||||
:key="field.key"
|
:key="field.key"
|
||||||
@ -117,7 +118,7 @@ import EmptyIndex from '@/management/components/EmptyIndex.vue'
|
|||||||
import CooperModify from '@/management/components/CooperModify/ModifyDialog.vue'
|
import CooperModify from '@/management/components/CooperModify/ModifyDialog.vue'
|
||||||
import { CODE_MAP } from '@/management/api/base'
|
import { CODE_MAP } from '@/management/api/base'
|
||||||
import { QOP_MAP } from '@/management/utils/constant.ts'
|
import { QOP_MAP } from '@/management/utils/constant.ts'
|
||||||
import { deleteSurvey } from '@/management/api/survey'
|
import { deleteSurvey,pausingSurvey } from '@/management/api/survey'
|
||||||
import { useWorkSpaceStore } from '@/management/stores/workSpace'
|
import { useWorkSpaceStore } from '@/management/stores/workSpace'
|
||||||
import { useSurveyListStore } from '@/management/stores/surveyList'
|
import { useSurveyListStore } from '@/management/stores/surveyList'
|
||||||
import ModifyDialog from './ModifyDialog.vue'
|
import ModifyDialog from './ModifyDialog.vue'
|
||||||
@ -134,7 +135,9 @@ import {
|
|||||||
noListDataConfig,
|
noListDataConfig,
|
||||||
noSearchDataConfig,
|
noSearchDataConfig,
|
||||||
selectOptionsDict,
|
selectOptionsDict,
|
||||||
buttonOptionsDict
|
buttonOptionsDict,
|
||||||
|
curStatus,
|
||||||
|
subStatus
|
||||||
} from '@/management/config/listConfig'
|
} from '@/management/config/listConfig'
|
||||||
|
|
||||||
const surveyListStore = useSurveyListStore()
|
const surveyListStore = useSurveyListStore()
|
||||||
@ -156,7 +159,7 @@ const props = defineProps({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
const emit = defineEmits(['refresh'])
|
const emit = defineEmits(['refresh'])
|
||||||
const fields = ['type', 'title', 'remark', 'owner', 'state', 'createDate', 'updateDate']
|
const fields = ['type', 'title', 'remark', 'owner', 'state', 'createdAt', 'updatedAt']
|
||||||
const showModify = ref(false)
|
const showModify = ref(false)
|
||||||
const modifyType = ref('')
|
const modifyType = ref('')
|
||||||
const questionInfo = ref({})
|
const questionInfo = ref({})
|
||||||
@ -191,42 +194,12 @@ const dataList = computed(() => {
|
|||||||
return data.value.map((item) => {
|
return data.value.map((item) => {
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
'curStatus.date': item.curStatus.date
|
'curStatus.date': item.curStatus.date,
|
||||||
|
'subStatus.date': item.subStatus.date
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
const filter = computed(() => {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
comparator: '',
|
|
||||||
condition: [
|
|
||||||
{
|
|
||||||
field: 'title',
|
|
||||||
value: searchVal.value,
|
|
||||||
comparator: '$regex'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
comparator: '',
|
|
||||||
condition: [
|
|
||||||
{
|
|
||||||
field: 'curStatus.status',
|
|
||||||
value: selectValueMap.value['curStatus.status']
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
comparator: '',
|
|
||||||
condition: [
|
|
||||||
{
|
|
||||||
field: 'surveyType',
|
|
||||||
value: selectValueMap.value.surveyType
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
const order = computed(() => {
|
const order = computed(() => {
|
||||||
const formatOrder = Object.entries(buttonValueMap.value)
|
const formatOrder = Object.entries(buttonValueMap.value)
|
||||||
.filter(([, effectValue]) => effectValue)
|
.filter(([, effectValue]) => effectValue)
|
||||||
@ -239,14 +212,8 @@ const order = computed(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const onRefresh = async () => {
|
const onRefresh = async () => {
|
||||||
const filterString = JSON.stringify(
|
|
||||||
filter.value.filter((item) => {
|
|
||||||
return item.condition[0].value
|
|
||||||
})
|
|
||||||
)
|
|
||||||
let params = {
|
let params = {
|
||||||
curPage: currentPage.value,
|
curPage: currentPage.value,
|
||||||
filter: filterString,
|
|
||||||
order: order.value
|
order: order.value
|
||||||
}
|
}
|
||||||
if (workSpaceId.value) {
|
if (workSpaceId.value) {
|
||||||
@ -280,6 +247,10 @@ const getToolConfig = (row) => {
|
|||||||
key: 'release',
|
key: 'release',
|
||||||
label: '投放'
|
label: '投放'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: subStatus.pausing.value,
|
||||||
|
label: '暂停'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: 'cooper',
|
key: 'cooper',
|
||||||
label: '协作'
|
label: '协作'
|
||||||
@ -300,6 +271,10 @@ const getToolConfig = (row) => {
|
|||||||
if (row.currentPermissions.includes(SurveyPermissions.SurveyManage)) {
|
if (row.currentPermissions.includes(SurveyPermissions.SurveyManage)) {
|
||||||
// 协作人判断权限显示投放按钮
|
// 协作人判断权限显示投放按钮
|
||||||
funcList.push(
|
funcList.push(
|
||||||
|
{
|
||||||
|
key: subStatus.pausing.value,
|
||||||
|
label: '暂停'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: QOP_MAP.EDIT,
|
key: QOP_MAP.EDIT,
|
||||||
label: '修改'
|
label: '修改'
|
||||||
@ -333,7 +308,12 @@ const getToolConfig = (row) => {
|
|||||||
permissionsBtn.splice(-1)
|
permissionsBtn.splice(-1)
|
||||||
funcList = permissionsBtn
|
funcList = permissionsBtn
|
||||||
}
|
}
|
||||||
const order = ['edit', 'analysis', 'release', 'delete', 'copy', 'cooper']
|
const order = ['edit', 'analysis', 'release', 'pausing', 'delete', 'copy', 'cooper']
|
||||||
|
if (row.curStatus.status === curStatus.new.value || row.subStatus.status === subStatus.pausing.value) {
|
||||||
|
// 去掉暂停按钮
|
||||||
|
order.splice(3, 1)
|
||||||
|
funcList = funcList.filter(item => item.key !== subStatus.pausing.value)
|
||||||
|
}
|
||||||
const result = funcList.sort((a, b) => order.indexOf(a.key) - order.indexOf(b.key))
|
const result = funcList.sort((a, b) => order.indexOf(a.key) - order.indexOf(b.key))
|
||||||
|
|
||||||
return result
|
return result
|
||||||
@ -368,6 +348,9 @@ const handleClick = (key, data) => {
|
|||||||
case 'cooper':
|
case 'cooper':
|
||||||
onCooper(data)
|
onCooper(data)
|
||||||
return
|
return
|
||||||
|
case 'pausing':
|
||||||
|
onPausing(data)
|
||||||
|
return
|
||||||
default:
|
default:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -392,6 +375,26 @@ const onDelete = async (row) => {
|
|||||||
ElMessage.error(res.errmsg || '删除失败')
|
ElMessage.error(res.errmsg || '删除失败')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const onPausing = async (row) => {
|
||||||
|
try {
|
||||||
|
await ElMessageBox.confirm('“暂停回收”后问卷将不能填写,是否继续?', '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
console.log('取消暂停')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const res = await pausingSurvey(row._id)
|
||||||
|
if (res.code === CODE_MAP.SUCCESS) {
|
||||||
|
ElMessage.success('暂停成功')
|
||||||
|
onRefresh()
|
||||||
|
} else {
|
||||||
|
ElMessage.error(res.errmsg || '暂停失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
const handleCurrentChange = (current) => {
|
const handleCurrentChange = (current) => {
|
||||||
currentPage.value = current
|
currentPage.value = current
|
||||||
onRefresh()
|
onRefresh()
|
||||||
|
@ -109,7 +109,7 @@ const props = defineProps({
|
|||||||
})
|
})
|
||||||
const emit = defineEmits(['refresh'])
|
const emit = defineEmits(['refresh'])
|
||||||
const workSpaceStore = useWorkSpaceStore()
|
const workSpaceStore = useWorkSpaceStore()
|
||||||
const fields = ['name', 'surveyTotal', 'memberTotal', 'owner', 'createDate']
|
const fields = ['name', 'surveyTotal', 'memberTotal', 'owner', 'createdAt']
|
||||||
const fieldList = computed(() => {
|
const fieldList = computed(() => {
|
||||||
return map(fields, (f) => {
|
return map(fields, (f) => {
|
||||||
return get(spaceListConfig, f, null)
|
return get(spaceListConfig, f, null)
|
||||||
|
@ -1,23 +1,23 @@
|
|||||||
<template>
|
<template>
|
||||||
<div :class="['list-state', 'list-state-' + value.curStatus?.status]">
|
<div :class="['list-state', 'list-state-' + status]">
|
||||||
<span class="list-state-badge" />
|
<span class="list-state-badge" />
|
||||||
<span>{{ statusMaps[value.curStatus?.status] }}</span>
|
<span>{{ statusMaps[status] }}</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup>
|
||||||
|
import { computed } from 'vue'
|
||||||
import { statusMaps } from '@/management/config/listConfig'
|
import { statusMaps } from '@/management/config/listConfig'
|
||||||
export default {
|
const props = defineProps({
|
||||||
name: 'StateModule',
|
value: {
|
||||||
props: {
|
type: Object,
|
||||||
value: Object
|
default: () => ({})
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
statusMaps
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
const status = computed(() => {
|
||||||
|
const {curStatus,subStatus } = props.value;
|
||||||
|
return subStatus?.status || curStatus?.status;
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@ -30,6 +30,12 @@ export default {
|
|||||||
background: $normal-color;
|
background: $normal-color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&-pausing{
|
||||||
|
color: #EB505C;
|
||||||
|
.list-state-badge {
|
||||||
|
background: #EB505C;
|
||||||
|
}
|
||||||
|
}
|
||||||
&-published {
|
&-published {
|
||||||
color: #0dbd93;
|
color: #0dbd93;
|
||||||
.list-state-badge {
|
.list-state-badge {
|
||||||
|
@ -157,6 +157,7 @@ const onCloseModify = (type: string) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const onSpaceCreate = () => {
|
const onSpaceCreate = () => {
|
||||||
|
modifyType.value = 'add'
|
||||||
showSpaceModify.value = true
|
showSpaceModify.value = true
|
||||||
}
|
}
|
||||||
const onCreate = () => {
|
const onCreate = () => {
|
||||||
|
@ -183,7 +183,6 @@ export const useEditStore = defineStore('edit', () => {
|
|||||||
surveyId,
|
surveyId,
|
||||||
sessionId,
|
sessionId,
|
||||||
setSurveyId,
|
setSurveyId,
|
||||||
|
|
||||||
cooperPermissions,
|
cooperPermissions,
|
||||||
fetchCooperPermissions,
|
fetchCooperPermissions,
|
||||||
|
|
||||||
|
@ -9,16 +9,29 @@ import { getSurveyList as getSurveyListReq } from '@/management/api/survey'
|
|||||||
|
|
||||||
import { useWorkSpaceStore } from './workSpace'
|
import { useWorkSpaceStore } from './workSpace'
|
||||||
|
|
||||||
|
import {
|
||||||
|
curStatus,
|
||||||
|
subStatus,
|
||||||
|
curStatusKey,
|
||||||
|
subStatusKey
|
||||||
|
} from '@/management/config/listConfig'
|
||||||
|
|
||||||
|
const verdictStatus = (status:never) => {
|
||||||
|
if(curStatus[status]) return curStatusKey
|
||||||
|
if (subStatus[status]) return subStatusKey
|
||||||
|
return curStatusKey
|
||||||
|
}
|
||||||
|
|
||||||
function useSearchSurvey() {
|
function useSearchSurvey() {
|
||||||
const searchVal = ref('')
|
const searchVal = ref('')
|
||||||
const selectValueMap = ref<Record<string, any>>({
|
const selectValueMap = ref<Record<string, any>>({
|
||||||
surveyType: '',
|
surveyType: '',
|
||||||
'curStatus.status': ''
|
'status': '',
|
||||||
})
|
})
|
||||||
|
|
||||||
const buttonValueMap = ref<Record<string, any>>({
|
const buttonValueMap = ref<Record<string, any>>({
|
||||||
'curStatus.date': '',
|
'updatedAt': '',
|
||||||
createDate: -1
|
createdAt: -1
|
||||||
})
|
})
|
||||||
|
|
||||||
const listFilter = computed(() => {
|
const listFilter = computed(() => {
|
||||||
@ -37,8 +50,8 @@ function useSearchSurvey() {
|
|||||||
comparator: '',
|
comparator: '',
|
||||||
condition: [
|
condition: [
|
||||||
{
|
{
|
||||||
field: 'curStatus.status',
|
field: verdictStatus( selectValueMap.value['status'] as never),
|
||||||
value: selectValueMap.value['curStatus.status']
|
value: selectValueMap.value['status']
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -67,14 +80,14 @@ function useSearchSurvey() {
|
|||||||
function resetSelectValueMap() {
|
function resetSelectValueMap() {
|
||||||
selectValueMap.value = {
|
selectValueMap.value = {
|
||||||
surveyType: '',
|
surveyType: '',
|
||||||
'curStatus.status': ''
|
'status': ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetButtonValueMap() {
|
function resetButtonValueMap() {
|
||||||
buttonValueMap.value = {
|
buttonValueMap.value = {
|
||||||
'curStatus.date': '',
|
'updatedAt': '',
|
||||||
createDate: -1
|
createdAt: -1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ export interface SpaceDetail {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type SpaceItem = Required<Omit<SpaceDetail, 'members'>> & {
|
export type SpaceItem = Required<Omit<SpaceDetail, 'members'>> & {
|
||||||
createDate: string
|
createdAt: string
|
||||||
curStatus: { date: number; status: string }
|
curStatus: { date: number; status: string }
|
||||||
memberTotal: number
|
memberTotal: number
|
||||||
currentUserRole: string
|
currentUserRole: string
|
||||||
|
@ -47,7 +47,7 @@ export default defineComponent({
|
|||||||
voteTotal: {
|
voteTotal: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 10
|
default: 10
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
emits: ['change'],
|
emits: ['change'],
|
||||||
setup(props, { emit, slots }) {
|
setup(props, { emit, slots }) {
|
||||||
|
@ -41,10 +41,11 @@ export default defineComponent({
|
|||||||
maxNum: {
|
maxNum: {
|
||||||
type: [Number, String],
|
type: [Number, String],
|
||||||
default: 1
|
default: 1
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
emits: ['change'],
|
emits: ['change'],
|
||||||
setup(props, { emit }) {
|
setup(props, { emit }) {
|
||||||
|
|
||||||
const disableState = computed(() => {
|
const disableState = computed(() => {
|
||||||
if (!props.maxNum) {
|
if (!props.maxNum) {
|
||||||
return false
|
return false
|
||||||
|
@ -134,9 +134,9 @@ const meta = {
|
|||||||
return moduleConfig?.options?.length
|
return moduleConfig?.options?.length
|
||||||
},
|
},
|
||||||
contentClass: 'input-number-config'
|
contentClass: 'input-number-config'
|
||||||
}
|
},
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
editConfigure: {
|
editConfigure: {
|
||||||
optionEdit: {
|
optionEdit: {
|
||||||
|
@ -13,6 +13,7 @@ import { ElMessage } from 'element-plus'
|
|||||||
import 'element-plus/theme-chalk/src/message.scss'
|
import 'element-plus/theme-chalk/src/message.scss'
|
||||||
import { FORM_CHANGE_EVENT_KEY } from '@/materials/setters/constant'
|
import { FORM_CHANGE_EVENT_KEY } from '@/materials/setters/constant'
|
||||||
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
formConfig: any
|
formConfig: any
|
||||||
moduleConfig: any
|
moduleConfig: any
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user