fix: 断点续答and编辑检测代码cr优化 (#428)
* fix: 优化代码以及去掉无用字段 * fix: 断点续答验收问题优化 * fix: 优化字段 * fix: lint * fix: 编辑检测相关问题优化 * fix: lint * fix: 第二批cr优化 * fix: 去掉无用代码 * fix: 调整session守卫位置 * fix: 文件大小写
This commit is contained in:
parent
628872f27c
commit
bf5db3f47b
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,7 +3,6 @@ node_modules
|
|||||||
dist
|
dist
|
||||||
|
|
||||||
package-lock.json
|
package-lock.json
|
||||||
yarn.lock
|
|
||||||
|
|
||||||
# local env files
|
# local env files
|
||||||
.env.local
|
.env.local
|
||||||
|
@ -48,8 +48,7 @@
|
|||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.1.13",
|
||||||
"rxjs": "^7.8.1",
|
"rxjs": "^7.8.1",
|
||||||
"svg-captcha": "^1.4.0",
|
"svg-captcha": "^1.4.0",
|
||||||
"typeorm": "^0.3.19",
|
"typeorm": "^0.3.19"
|
||||||
"xss": "^1.0.15"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@nestjs/cli": "^10.0.0",
|
"@nestjs/cli": "^10.0.0",
|
||||||
|
@ -6,7 +6,7 @@ export enum RECORD_STATUS {
|
|||||||
PUBLISHED = 'published', // 发布
|
PUBLISHED = 'published', // 发布
|
||||||
REMOVED = 'removed', // 删除
|
REMOVED = 'removed', // 删除
|
||||||
FORCE_REMOVED = 'forceRemoved', // 从回收站删除
|
FORCE_REMOVED = 'forceRemoved', // 从回收站删除
|
||||||
COMOPUTETING = 'computing', // 计算中
|
COMPUTING = 'computing', // 计算中
|
||||||
FINISHED = 'finished', // 已完成
|
FINISHED = 'finished', // 已完成
|
||||||
ERROR = 'error', // 错误
|
ERROR = 'error', // 错误
|
||||||
}
|
}
|
||||||
|
@ -2,25 +2,16 @@ import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
|
|||||||
import { Reflector } from '@nestjs/core';
|
import { Reflector } from '@nestjs/core';
|
||||||
import { get } from 'lodash';
|
import { get } from 'lodash';
|
||||||
import { NoPermissionException } from 'src/exceptions/noPermissionException';
|
import { NoPermissionException } from 'src/exceptions/noPermissionException';
|
||||||
import { SurveyNotFoundException } from 'src/exceptions/surveyNotFoundException';
|
|
||||||
import { SessionService } from 'src/modules/survey/services/session.service';
|
import { SessionService } from 'src/modules/survey/services/session.service';
|
||||||
import { SurveyMetaService } from 'src/modules/survey/services/surveyMeta.service';
|
|
||||||
import { WorkspaceMemberService } from 'src/modules/workspace/services/workspaceMember.service';
|
|
||||||
import { CollaboratorService } from 'src/modules/survey/services/collaborator.service';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SessionGuard implements CanActivate {
|
export class SessionGuard implements CanActivate {
|
||||||
constructor(
|
constructor(
|
||||||
private reflector: Reflector,
|
private reflector: Reflector,
|
||||||
private readonly sessionService: SessionService,
|
private readonly sessionService: SessionService,
|
||||||
private readonly surveyMetaService: SurveyMetaService,
|
|
||||||
private readonly workspaceMemberService: WorkspaceMemberService,
|
|
||||||
private readonly collaboratorService: CollaboratorService,
|
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||||
const request = context.switchToHttp().getRequest();
|
const request = context.switchToHttp().getRequest();
|
||||||
const user = request.user;
|
|
||||||
const sessionIdKey = this.reflector.get<string>(
|
const sessionIdKey = this.reflector.get<string>(
|
||||||
'sessionId',
|
'sessionId',
|
||||||
context.getHandler(),
|
context.getHandler(),
|
||||||
@ -31,64 +22,8 @@ export class SessionGuard implements CanActivate {
|
|||||||
if (!sessionId) {
|
if (!sessionId) {
|
||||||
throw new NoPermissionException('没有权限');
|
throw new NoPermissionException('没有权限');
|
||||||
}
|
}
|
||||||
|
const sessionInfo = await this.sessionService.findOne(sessionId);
|
||||||
const saveSession = await this.sessionService.findOne(sessionId);
|
request.sessionInfo = sessionInfo;
|
||||||
|
return true;
|
||||||
request.saveSession = saveSession;
|
|
||||||
|
|
||||||
const surveyId = saveSession.surveyId;
|
|
||||||
|
|
||||||
const surveyMeta = await this.surveyMetaService.getSurveyById({ surveyId });
|
|
||||||
|
|
||||||
if (!surveyMeta) {
|
|
||||||
throw new SurveyNotFoundException('问卷不存在');
|
|
||||||
}
|
|
||||||
|
|
||||||
request.surveyMeta = surveyMeta;
|
|
||||||
|
|
||||||
// 兼容老的问卷没有ownerId
|
|
||||||
if (
|
|
||||||
surveyMeta.ownerId === user._id.toString() ||
|
|
||||||
surveyMeta.owner === user.username
|
|
||||||
) {
|
|
||||||
// 问卷的owner,可以访问和操作问卷
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (surveyMeta.workspaceId) {
|
|
||||||
const memberInfo = await this.workspaceMemberService.findOne({
|
|
||||||
workspaceId: surveyMeta.workspaceId,
|
|
||||||
userId: user._id.toString(),
|
|
||||||
});
|
|
||||||
if (!memberInfo) {
|
|
||||||
throw new NoPermissionException('没有权限');
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const permissions = this.reflector.get<string[]>(
|
|
||||||
'surveyPermission',
|
|
||||||
context.getHandler(),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!Array.isArray(permissions) || permissions.length === 0) {
|
|
||||||
throw new NoPermissionException('没有权限');
|
|
||||||
}
|
|
||||||
|
|
||||||
const info = await this.collaboratorService.getCollaborator({
|
|
||||||
surveyId,
|
|
||||||
userId: user._id.toString(),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!info) {
|
|
||||||
throw new NoPermissionException('没有权限');
|
|
||||||
}
|
|
||||||
request.collaborator = info;
|
|
||||||
if (
|
|
||||||
permissions.some((permission) => info.permissions.includes(permission))
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
throw new NoPermissionException('没有权限');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,4 @@ export class SurveyHistory extends BaseEntity {
|
|||||||
username: string;
|
username: string;
|
||||||
_id: string;
|
_id: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
@Column('string')
|
|
||||||
sessionId: string;
|
|
||||||
}
|
}
|
||||||
|
@ -35,13 +35,4 @@ export class AuthService {
|
|||||||
}
|
}
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
async expiredCheck(token: string) {
|
|
||||||
try {
|
|
||||||
verify(token, this.configService.get<string>('XIAOJU_SURVEY_JWT_SECRET'));
|
|
||||||
} catch (err) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,6 @@ describe('SurveyHistoryService', () => {
|
|||||||
schema,
|
schema,
|
||||||
type,
|
type,
|
||||||
user,
|
user,
|
||||||
sessionId: '',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(spyCreate).toHaveBeenCalledWith({
|
expect(spyCreate).toHaveBeenCalledWith({
|
||||||
|
@ -67,7 +67,9 @@ export class SessionController {
|
|||||||
|
|
||||||
@Post('/seize')
|
@Post('/seize')
|
||||||
@HttpCode(200)
|
@HttpCode(200)
|
||||||
|
@UseGuards(SurveyGuard)
|
||||||
@UseGuards(SessionGuard)
|
@UseGuards(SessionGuard)
|
||||||
|
|
||||||
@SetMetadata('sessionId', 'body.sessionId')
|
@SetMetadata('sessionId', 'body.sessionId')
|
||||||
@SetMetadata('surveyPermission', [SURVEY_PERMISSION.SURVEY_CONF_MANAGE])
|
@SetMetadata('surveyPermission', [SURVEY_PERMISSION.SURVEY_CONF_MANAGE])
|
||||||
@UseGuards(Authentication)
|
@UseGuards(Authentication)
|
||||||
@ -75,11 +77,11 @@ export class SessionController {
|
|||||||
@Request()
|
@Request()
|
||||||
req,
|
req,
|
||||||
) {
|
) {
|
||||||
const saveSession = req.saveSession;
|
const sessionInfo = req.sessionInfo;
|
||||||
|
|
||||||
await this.sessionService.updateSessionToEditing({
|
await this.sessionService.updateSessionToEditing({
|
||||||
sessionId: saveSession._id.toString(),
|
sessionId: sessionInfo._id.toString(),
|
||||||
surveyId: saveSession.surveyId,
|
surveyId: sessionInfo.surveyId,
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -156,7 +156,7 @@ export class DownloadTaskService {
|
|||||||
{
|
{
|
||||||
$set: {
|
$set: {
|
||||||
curStatus: {
|
curStatus: {
|
||||||
status: RECORD_STATUS.COMOPUTETING,
|
status: RECORD_STATUS.COMPUTING,
|
||||||
date: Date.now(),
|
date: Date.now(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -43,7 +43,6 @@
|
|||||||
"options": [
|
"options": [
|
||||||
{
|
{
|
||||||
"text": "选项1",
|
"text": "选项1",
|
||||||
"imageUrl": "",
|
|
||||||
"others": false,
|
"others": false,
|
||||||
"mustOthers": false,
|
"mustOthers": false,
|
||||||
"othersKey": "",
|
"othersKey": "",
|
||||||
@ -52,7 +51,6 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"text": "选项2",
|
"text": "选项2",
|
||||||
"imageUrl": "",
|
|
||||||
"others": false,
|
"others": false,
|
||||||
"mustOthers": false,
|
"mustOthers": false,
|
||||||
"othersKey": "",
|
"othersKey": "",
|
||||||
|
@ -47,7 +47,6 @@
|
|||||||
{
|
{
|
||||||
"text": "课程1",
|
"text": "课程1",
|
||||||
"hash": "115019",
|
"hash": "115019",
|
||||||
"imageUrl": "",
|
|
||||||
"others": false,
|
"others": false,
|
||||||
"mustOthers": false,
|
"mustOthers": false,
|
||||||
"othersKey": "",
|
"othersKey": "",
|
||||||
@ -56,7 +55,6 @@
|
|||||||
{
|
{
|
||||||
"text": "课程2",
|
"text": "课程2",
|
||||||
"hash": "115020",
|
"hash": "115020",
|
||||||
"imageUrl": "",
|
|
||||||
"others": false,
|
"others": false,
|
||||||
"mustOthers": false,
|
"mustOthers": false,
|
||||||
"othersKey": "",
|
"othersKey": "",
|
||||||
@ -65,7 +63,6 @@
|
|||||||
{
|
{
|
||||||
"text": "课程3",
|
"text": "课程3",
|
||||||
"hash": "115021",
|
"hash": "115021",
|
||||||
"imageUrl": "",
|
|
||||||
"others": false,
|
"others": false,
|
||||||
"mustOthers": false,
|
"mustOthers": false,
|
||||||
"othersKey": "",
|
"othersKey": "",
|
||||||
@ -74,7 +71,6 @@
|
|||||||
{
|
{
|
||||||
"text": "课程4",
|
"text": "课程4",
|
||||||
"hash": "115022",
|
"hash": "115022",
|
||||||
"imageUrl": "",
|
|
||||||
"others": false,
|
"others": false,
|
||||||
"mustOthers": false,
|
"mustOthers": false,
|
||||||
"othersKey": "",
|
"othersKey": "",
|
||||||
|
@ -46,7 +46,6 @@
|
|||||||
"options": [
|
"options": [
|
||||||
{
|
{
|
||||||
"text": "选项1",
|
"text": "选项1",
|
||||||
"imageUrl": "",
|
|
||||||
"others": false,
|
"others": false,
|
||||||
"mustOthers": false,
|
"mustOthers": false,
|
||||||
"othersKey": "",
|
"othersKey": "",
|
||||||
@ -55,7 +54,6 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"text": "选项2",
|
"text": "选项2",
|
||||||
"imageUrl": "",
|
|
||||||
"others": false,
|
"others": false,
|
||||||
"mustOthers": false,
|
"mustOthers": false,
|
||||||
"othersKey": "",
|
"othersKey": "",
|
||||||
|
@ -51,6 +51,7 @@
|
|||||||
},
|
},
|
||||||
"pageConf": [],
|
"pageConf": [],
|
||||||
"logicConf": {
|
"logicConf": {
|
||||||
"showLogicConf": []
|
"showLogicConf": [],
|
||||||
|
"jumpLogicConf": []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,53 +0,0 @@
|
|||||||
import xss from 'xss';
|
|
||||||
|
|
||||||
const myxss = new (xss as any).FilterXSS({
|
|
||||||
onIgnoreTagAttr(tag, name, value) {
|
|
||||||
if (name === 'style' || name === 'class') {
|
|
||||||
return `${name}="${value}"`;
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
},
|
|
||||||
onIgnoreTag(tag, html) {
|
|
||||||
// <xxx>过滤为空,否则不过滤为空
|
|
||||||
const re1 = new RegExp('<.+?>', 'g');
|
|
||||||
if (re1.test(html)) {
|
|
||||||
return '';
|
|
||||||
} else {
|
|
||||||
return html;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export const cleanRichTextWithMediaTag = (text) => {
|
|
||||||
if (!text) {
|
|
||||||
return text === 0 ? 0 : '';
|
|
||||||
}
|
|
||||||
const html = transformHtmlTag(text)
|
|
||||||
.replace(/<img([\w\W]+?)\/>/g, '[图片]')
|
|
||||||
.replace(/<video.*\/video>/g, '[视频]');
|
|
||||||
const content = html.replace(/<[^<>]+>/g, '').replace(/ /g, '');
|
|
||||||
|
|
||||||
return content;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function escapeHtml(html) {
|
|
||||||
return html.replace(/</g, '<').replace(/>/g, '>');
|
|
||||||
}
|
|
||||||
export const transformHtmlTag = (html) => {
|
|
||||||
if (!html) return '';
|
|
||||||
if (typeof html !== 'string') return html + '';
|
|
||||||
return html
|
|
||||||
.replace(html ? /&(?!#?\w+;)/g : /&/g, '&')
|
|
||||||
.replace(/</g, '<')
|
|
||||||
.replace(/>/g, '>')
|
|
||||||
.replace(/"/g, '"')
|
|
||||||
.replace(/'/g, "'")
|
|
||||||
.replace(/\\\n/g, '\\n');
|
|
||||||
//.replace(/ /g, "")
|
|
||||||
};
|
|
||||||
|
|
||||||
const filterXSSClone = myxss.process.bind(myxss);
|
|
||||||
|
|
||||||
export const filterXSS = (html) => filterXSSClone(transformHtmlTag(html));
|
|
||||||
|
|
||||||
export const escapeFilterXSS = (html) => escapeHtml(filterXSS(html));
|
|
58
web/src/common/localstorage.ts
Normal file
58
web/src/common/localstorage.ts
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
interface ExtendedItem {
|
||||||
|
value: any
|
||||||
|
expires?: number // 可选属性
|
||||||
|
}
|
||||||
|
|
||||||
|
const localstorage = {
|
||||||
|
// 检查是否支持localStorage
|
||||||
|
isSupported(): boolean {
|
||||||
|
return typeof window !== 'undefined' && 'localStorage' in window
|
||||||
|
},
|
||||||
|
|
||||||
|
// 设置值
|
||||||
|
setItem(key: string, value: any, expires?: number): void {
|
||||||
|
if (!this.isSupported()) return
|
||||||
|
|
||||||
|
let item: ExtendedItem = { value }
|
||||||
|
|
||||||
|
if (expires !== undefined) {
|
||||||
|
item = { ...item, expires: Date.now() + expires * 1000 }
|
||||||
|
}
|
||||||
|
|
||||||
|
const serializedValue = JSON.stringify(item)
|
||||||
|
|
||||||
|
localStorage.setItem(key, serializedValue)
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取值
|
||||||
|
getItem<T>(key: string): T | null {
|
||||||
|
if (!this.isSupported()) return null
|
||||||
|
|
||||||
|
const serializedValue = localStorage.getItem(key) as string
|
||||||
|
if (!serializedValue) return null
|
||||||
|
|
||||||
|
let item: any
|
||||||
|
try {
|
||||||
|
item = JSON.parse(serializedValue)
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error parsing JSON from localStorage')
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.expires && item.expires < Date.now()) {
|
||||||
|
this.removeItem(key)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return item.value as T
|
||||||
|
},
|
||||||
|
|
||||||
|
// 移除值
|
||||||
|
removeItem(key: string): void {
|
||||||
|
if (!this.isSupported()) return
|
||||||
|
|
||||||
|
localStorage.removeItem(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default localstorage
|
@ -9,7 +9,7 @@ const myxss = new xss.FilterXSS({
|
|||||||
},
|
},
|
||||||
onIgnoreTag(tag, html) {
|
onIgnoreTag(tag, html) {
|
||||||
// <xxx>过滤为空,否则不过滤为空
|
// <xxx>过滤为空,否则不过滤为空
|
||||||
var re1 = new RegExp('<.+?>', 'g')
|
const re1 = new RegExp('<.+?>', 'g')
|
||||||
if (re1.test(html)) {
|
if (re1.test(html)) {
|
||||||
return ''
|
return ''
|
||||||
} else {
|
} else {
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { watch } from 'vue'
|
import { watch, onBeforeUnmount } from 'vue'
|
||||||
import { get as _get } from 'lodash-es'
|
import { get as _get } from 'lodash-es'
|
||||||
import { useUserStore } from '@/management/stores/user'
|
import { useUserStore } from '@/management/stores/user'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
@ -23,11 +23,11 @@ const showConfirmBox = () => {
|
|||||||
showClose: false,
|
showClose: false,
|
||||||
callback: (action: Action) => {
|
callback: (action: Action) => {
|
||||||
if (action === 'confirm') {
|
if (action === 'confirm') {
|
||||||
userStore.logout();
|
userStore.logout()
|
||||||
router.replace({ name: 'login' });
|
router.replace({ name: 'login' })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const checkAuth = async () => {
|
const checkAuth = async () => {
|
||||||
@ -41,32 +41,40 @@ const checkAuth = async () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
if (res.data.code !== 200) {
|
if (res.data.code !== 200) {
|
||||||
showConfirmBox();
|
showConfirmBox()
|
||||||
} else {
|
} else {
|
||||||
timer = setTimeout(() => {
|
timer = setTimeout(
|
||||||
checkAuth()
|
() => {
|
||||||
}, 30 * 60 * 1000);
|
checkAuth()
|
||||||
|
},
|
||||||
|
30 * 60 * 1000
|
||||||
|
)
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const e = error as any
|
const e = error as any
|
||||||
ElMessage.error(e.message)
|
ElMessage.error(e.message)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(() => userStore.hasLogined, (hasLogined) => {
|
watch(
|
||||||
if (hasLogined) {
|
() => userStore.hasLogined,
|
||||||
timer = setTimeout(() => {
|
(hasLogined) => {
|
||||||
checkAuth()
|
if (hasLogined) {
|
||||||
}, 30 * 60 * 1000);
|
timer = setTimeout(
|
||||||
} else {
|
() => {
|
||||||
clearTimeout(timer);
|
checkAuth()
|
||||||
|
},
|
||||||
|
30 * 60 * 1000
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
clearTimeout(timer)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
clearTimeout(timer)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
@ -16,4 +16,3 @@ export const getStatisticList = (data) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,11 +7,10 @@ export const createDownloadSurveyResponseTask = ({ surveyId, isDesensitive }) =>
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getDownloadTask = taskId => {
|
export const getDownloadTask = (taskId) => {
|
||||||
return axios.get('/downloadTask/getDownloadTask', { params: { taskId } })
|
return axios.get('/downloadTask/getDownloadTask', { params: { taskId } })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const getDownloadTaskList = ({ pageIndex, pageSize }) => {
|
export const getDownloadTaskList = ({ pageIndex, pageSize }) => {
|
||||||
return axios.get('/downloadTask/getDownloadTaskList', {
|
return axios.get('/downloadTask/getDownloadTaskList', {
|
||||||
params: {
|
params: {
|
||||||
@ -24,6 +23,6 @@ export const getDownloadTaskList = ({ pageIndex, pageSize }) => {
|
|||||||
//问卷删除
|
//问卷删除
|
||||||
export const deleteDownloadTask = (taskId) => {
|
export const deleteDownloadTask = (taskId) => {
|
||||||
return axios.post('/downloadTask/deleteDownloadTask', {
|
return axios.post('/downloadTask/deleteDownloadTask', {
|
||||||
taskId,
|
taskId
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -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 ''
|
||||||
|
@ -28,13 +28,8 @@
|
|||||||
<EmptyIndex :data="noDataConfig" />
|
<EmptyIndex :data="noDataConfig" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-dialog
|
<el-dialog v-model="downloadDialogVisible" title="导出确认" width="500" style="padding: 40px">
|
||||||
v-model="downloadDialogVisible"
|
<el-form :model="downloadForm" label-width="100px" label-position="left">
|
||||||
title="导出确认"
|
|
||||||
width="500"
|
|
||||||
style="padding: 40px;"
|
|
||||||
>
|
|
||||||
<el-form :model="downloadForm" label-width="100px" label-position="left" >
|
|
||||||
<el-form-item label="导出内容">
|
<el-form-item label="导出内容">
|
||||||
<el-radio-group v-model="downloadForm.isDesensitive">
|
<el-radio-group v-model="downloadForm.isDesensitive">
|
||||||
<el-radio :value="true">脱敏数据</el-radio>
|
<el-radio :value="true">脱敏数据</el-radio>
|
||||||
@ -52,9 +47,7 @@
|
|||||||
<template #footer>
|
<template #footer>
|
||||||
<div class="dialog-footer">
|
<div class="dialog-footer">
|
||||||
<el-button @click="downloadDialogVisible = false">取消</el-button>
|
<el-button @click="downloadDialogVisible = false">取消</el-button>
|
||||||
<el-button type="primary" @click="confirmDownload()">
|
<el-button type="primary" @click="confirmDownload()"> 确认 </el-button>
|
||||||
确认
|
|
||||||
</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
@ -85,11 +78,12 @@ const dataTableState = reactive({
|
|||||||
isDownloading: false,
|
isDownloading: false,
|
||||||
downloadDialogVisible: false,
|
downloadDialogVisible: false,
|
||||||
downloadForm: {
|
downloadForm: {
|
||||||
isDesensitive: true,
|
isDesensitive: true
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const { mainTableLoading, tableData, isShowOriginData, downloadDialogVisible, isDownloading } = toRefs(dataTableState)
|
const { mainTableLoading, tableData, isShowOriginData, downloadDialogVisible, isDownloading } =
|
||||||
|
toRefs(dataTableState)
|
||||||
const downloadForm = dataTableState.downloadForm
|
const downloadForm = dataTableState.downloadForm
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
@ -168,7 +162,10 @@ const confirmDownload = async () => {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
isDownloading.value = true
|
isDownloading.value = true
|
||||||
const createRes = await createDownloadSurveyResponseTask({ surveyId: route.params.id, isDesensitive: downloadForm.isDesensitive })
|
const createRes = await createDownloadSurveyResponseTask({
|
||||||
|
surveyId: route.params.id,
|
||||||
|
isDesensitive: downloadForm.isDesensitive
|
||||||
|
})
|
||||||
dataTableState.downloadDialogVisible = false
|
dataTableState.downloadDialogVisible = false
|
||||||
if (createRes.code === 200) {
|
if (createRes.code === 200) {
|
||||||
ElMessage.success(`下载文件计算中,可前往“下载中心”查看`)
|
ElMessage.success(`下载文件计算中,可前往“下载中心”查看`)
|
||||||
@ -176,12 +173,11 @@ const confirmDownload = async () => {
|
|||||||
const taskInfo = await checkIsTaskFinished(createRes.data.taskId)
|
const taskInfo = await checkIsTaskFinished(createRes.data.taskId)
|
||||||
if (taskInfo.url) {
|
if (taskInfo.url) {
|
||||||
window.open(taskInfo.url)
|
window.open(taskInfo.url)
|
||||||
ElMessage.success("导出成功")
|
ElMessage.success('导出成功')
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ElMessage.error('导出失败,请重试')
|
ElMessage.error('导出失败,请重试')
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
ElMessage.error('导出失败,请重试')
|
ElMessage.error('导出失败,请重试')
|
||||||
}
|
}
|
||||||
@ -190,13 +186,12 @@ const confirmDownload = async () => {
|
|||||||
} finally {
|
} finally {
|
||||||
isDownloading.value = false
|
isDownloading.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const checkIsTaskFinished = (taskId) => {
|
const checkIsTaskFinished = (taskId) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
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.curStatus.status
|
||||||
if (status === 'new' || status === 'computing') {
|
if (status === 'new' || status === 'computing') {
|
||||||
@ -207,15 +202,13 @@ const checkIsTaskFinished = (taskId) => {
|
|||||||
resolve(res.data)
|
resolve(res.data)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
reject("导出失败");
|
reject('导出失败')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
run()
|
run()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@ -25,7 +25,13 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="操作" width="200">
|
<el-table-column label="操作" width="200">
|
||||||
<template v-slot="{ row }">
|
<template v-slot="{ row }">
|
||||||
<span v-if="row.curStatus?.status === 'finished'" class="text-btn download-btn" @click="handleDownload(row)"> 下载 </span>
|
<span
|
||||||
|
v-if="row.curStatus?.status === 'finished'"
|
||||||
|
class="text-btn download-btn"
|
||||||
|
@click="handleDownload(row)"
|
||||||
|
>
|
||||||
|
下载
|
||||||
|
</span>
|
||||||
<span class="text-btn delete-btn" @click="openDeleteDialog(row)"> 删除 </span>
|
<span class="text-btn delete-btn" @click="openDeleteDialog(row)"> 删除 </span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@ -71,14 +77,14 @@ const getList = async ({ pageIndex }: { pageIndex: number }) => {
|
|||||||
}
|
}
|
||||||
const params = {
|
const params = {
|
||||||
pageSize: pageSize.value,
|
pageSize: pageSize.value,
|
||||||
pageIndex,
|
pageIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
const res: Record<string, any> = await getDownloadTaskList(params)
|
const res: Record<string, any> = await getDownloadTaskList(params)
|
||||||
if (res.code === CODE_MAP.SUCCESS) {
|
if (res.code === CODE_MAP.SUCCESS) {
|
||||||
total.value = res.data.total
|
total.value = res.data.total
|
||||||
const list = res.data.list as any
|
const list = res.data.list as any
|
||||||
dataList.splice(0, dataList.length, ...list);
|
dataList.splice(0, dataList.length, ...list)
|
||||||
}
|
}
|
||||||
loading.value = false
|
loading.value = false
|
||||||
}
|
}
|
||||||
@ -87,8 +93,8 @@ const statusTextMap: Record<string, string> = {
|
|||||||
new: '排队中',
|
new: '排队中',
|
||||||
computing: '计算中',
|
computing: '计算中',
|
||||||
finished: '已完成',
|
finished: '已完成',
|
||||||
removed: '已删除',
|
removed: '已删除'
|
||||||
};
|
}
|
||||||
|
|
||||||
let currentDelRow: Record<string, any> = {}
|
let currentDelRow: Record<string, any> = {}
|
||||||
// 下载文件
|
// 下载文件
|
||||||
@ -123,11 +129,11 @@ const confirmDelete = async () => {
|
|||||||
if (res.code !== CODE_MAP.SUCCESS) {
|
if (res.code !== CODE_MAP.SUCCESS) {
|
||||||
ElMessage.error(res.errmsg)
|
ElMessage.error(res.errmsg)
|
||||||
} else {
|
} else {
|
||||||
ElMessage.success('删除成功');
|
ElMessage.success('删除成功')
|
||||||
await getList({ pageIndex: 1 })
|
await getList({ pageIndex: 1 })
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ElMessage.error("删除失败,请刷新重试")
|
ElMessage.error('删除失败,请刷新重试')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,7 +168,7 @@ const downloadListConfig = {
|
|||||||
formatter(row: Record<string, any>, column: Record<string, any>) {
|
formatter(row: Record<string, any>, column: Record<string, any>) {
|
||||||
console.log({
|
console.log({
|
||||||
row,
|
row,
|
||||||
column,
|
column
|
||||||
})
|
})
|
||||||
return statusTextMap[get(row, column.rawColumnKey)]
|
return statusTextMap[get(row, column.rawColumnKey)]
|
||||||
}
|
}
|
||||||
|
@ -18,10 +18,15 @@
|
|||||||
</CooperationPanel>
|
</CooperationPanel>
|
||||||
<PreviewPanel></PreviewPanel>
|
<PreviewPanel></PreviewPanel>
|
||||||
<HistoryPanel></HistoryPanel>
|
<HistoryPanel></HistoryPanel>
|
||||||
<SavePanel :updateLogicConf="updateLogicConf" :updateWhiteConf="updateWhiteConf"></SavePanel>
|
<SavePanel
|
||||||
|
:updateLogicConf="updateLogicConf"
|
||||||
|
:updateWhiteConf="updateWhiteConf"
|
||||||
|
:seize="seize"
|
||||||
|
></SavePanel>
|
||||||
<PublishPanel
|
<PublishPanel
|
||||||
:updateLogicConf="updateLogicConf"
|
:updateLogicConf="updateLogicConf"
|
||||||
:updateWhiteConf="updateWhiteConf"
|
:updateWhiteConf="updateWhiteConf"
|
||||||
|
:seize="seize"
|
||||||
></PublishPanel>
|
></PublishPanel>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -30,6 +35,8 @@
|
|||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import { useEditStore } from '@/management/stores/edit'
|
import { useEditStore } from '@/management/stores/edit'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import 'element-plus/theme-chalk/src/message.scss'
|
||||||
|
|
||||||
import BackPanel from '../modules/generalModule/BackPanel.vue'
|
import BackPanel from '../modules/generalModule/BackPanel.vue'
|
||||||
import TitlePanel from '../modules/generalModule/TitlePanel.vue'
|
import TitlePanel from '../modules/generalModule/TitlePanel.vue'
|
||||||
@ -39,6 +46,7 @@ import PreviewPanel from '../modules/contentModule/PreviewPanel.vue'
|
|||||||
import SavePanel from '../modules/contentModule/SavePanel.vue'
|
import SavePanel from '../modules/contentModule/SavePanel.vue'
|
||||||
import PublishPanel from '../modules/contentModule/PublishPanel.vue'
|
import PublishPanel from '../modules/contentModule/PublishPanel.vue'
|
||||||
import CooperationPanel from '../modules/contentModule/CooperationPanel.vue'
|
import CooperationPanel from '../modules/contentModule/CooperationPanel.vue'
|
||||||
|
import { seizeSession } from '@/management/api/survey'
|
||||||
|
|
||||||
const editStore = useEditStore()
|
const editStore = useEditStore()
|
||||||
const { schema, changeSchema } = editStore
|
const { schema, changeSchema } = editStore
|
||||||
@ -68,7 +76,7 @@ const updateLogicConf = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const showLogicConf = showLogicEngine.value.toJson()
|
const showLogicConf = showLogicEngine.value.toJson()
|
||||||
if(JSON.stringify(schema.logicConf.showLogicConf) !== JSON.stringify(showLogicConf)) {
|
if (JSON.stringify(schema.logicConf.showLogicConf) !== JSON.stringify(showLogicConf)) {
|
||||||
// 更新逻辑配置
|
// 更新逻辑配置
|
||||||
changeSchema({ key: 'logicConf', value: { showLogicConf } })
|
changeSchema({ key: 'logicConf', value: { showLogicConf } })
|
||||||
}
|
}
|
||||||
@ -76,7 +84,7 @@ const updateLogicConf = () => {
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
const jumpLogicConf = jumpLogicEngine.value.toJson()
|
const jumpLogicConf = jumpLogicEngine.value.toJson()
|
||||||
if(JSON.stringify(schema.logicConf.jumpLogicConf) !== JSON.stringify(jumpLogicConf)){
|
if (JSON.stringify(schema.logicConf.jumpLogicConf) !== JSON.stringify(jumpLogicConf)) {
|
||||||
changeSchema({ key: 'logicConf', value: { jumpLogicConf } })
|
changeSchema({ key: 'logicConf', value: { jumpLogicConf } })
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,6 +114,16 @@ const updateWhiteConf = () => {
|
|||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 重新获取sessionid
|
||||||
|
const seize = async (sessionId: string) => {
|
||||||
|
const seizeRes: Record<string, any> = await seizeSession({ sessionId })
|
||||||
|
if (seizeRes.code === 200) {
|
||||||
|
location.reload()
|
||||||
|
} else {
|
||||||
|
ElMessage.error('获取权限失败,请重试')
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import url('@/management/styles/edit-btn.scss');
|
@import url('@/management/styles/edit-btn.scss');
|
||||||
|
@ -24,7 +24,6 @@ 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 } = editStore
|
const { init, setSurveyId } = editStore
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ import { useEditStore } from '@/management/stores/edit'
|
|||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
import 'element-plus/theme-chalk/src/message.scss'
|
import 'element-plus/theme-chalk/src/message.scss'
|
||||||
import { publishSurvey, saveSurvey, seizeSession } from '@/management/api/survey'
|
import { publishSurvey, saveSurvey } from '@/management/api/survey'
|
||||||
import buildData from './buildData'
|
import buildData from './buildData'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
import { CODE_MAP } from '@/management/api/base'
|
import { CODE_MAP } from '@/management/api/base'
|
||||||
@ -17,6 +17,7 @@ import { CODE_MAP } from '@/management/api/base'
|
|||||||
interface Props {
|
interface Props {
|
||||||
updateLogicConf: any
|
updateLogicConf: any
|
||||||
updateWhiteConf: any
|
updateWhiteConf: any
|
||||||
|
seize: any
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<Props>()
|
const props = defineProps<Props>()
|
||||||
@ -29,15 +30,6 @@ const saveData = computed(() => {
|
|||||||
return buildData(schema.value, sessionId.value)
|
return buildData(schema.value, sessionId.value)
|
||||||
})
|
})
|
||||||
|
|
||||||
const seize = async () => {
|
|
||||||
const seizeRes: Record<string, any> = await seizeSession({ sessionId: sessionId.value })
|
|
||||||
if (seizeRes.code === 200) {
|
|
||||||
location.reload();
|
|
||||||
} else {
|
|
||||||
ElMessage.error('获取权限失败,请重试')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
const validate = () => {
|
const validate = () => {
|
||||||
@ -61,7 +53,6 @@ const validate = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const onSave = async () => {
|
const onSave = async () => {
|
||||||
|
|
||||||
if (!saveData.value.sessionId) {
|
if (!saveData.value.sessionId) {
|
||||||
ElMessage.error('未获取到sessionId')
|
ElMessage.error('未获取到sessionId')
|
||||||
return null
|
return null
|
||||||
@ -74,7 +65,7 @@ const onSave = async () => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const res: any = await saveSurvey(saveData.value)
|
const res: any = await saveSurvey(saveData.value)
|
||||||
if(!res) {
|
if (!res) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
@ -85,10 +76,10 @@ const onSave = async () => {
|
|||||||
confirmButtonText: '刷新同步',
|
confirmButtonText: '刷新同步',
|
||||||
callback: (action: string) => {
|
callback: (action: string) => {
|
||||||
if (action === 'confirm') {
|
if (action === 'confirm') {
|
||||||
seize();
|
props.seize(sessionId.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
return null
|
return null
|
||||||
} else {
|
} else {
|
||||||
ElMessage.error(res.errmsg)
|
ElMessage.error(res.errmsg)
|
||||||
@ -98,7 +89,6 @@ const onSave = async () => {
|
|||||||
ElMessage.error('保存问卷失败')
|
ElMessage.error('保存问卷失败')
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
const handlePublish = async () => {
|
const handlePublish = async () => {
|
||||||
if (isPublishing.value) {
|
if (isPublishing.value) {
|
||||||
|
@ -21,12 +21,13 @@ import { useEditStore } from '@/management/stores/edit'
|
|||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
import 'element-plus/theme-chalk/src/message.scss'
|
import 'element-plus/theme-chalk/src/message.scss'
|
||||||
|
|
||||||
import { saveSurvey, seizeSession } from '@/management/api/survey'
|
import { saveSurvey } from '@/management/api/survey'
|
||||||
import buildData from './buildData'
|
import buildData from './buildData'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
updateLogicConf: any
|
updateLogicConf: any
|
||||||
updateWhiteConf: any
|
updateWhiteConf: any
|
||||||
|
seize: any
|
||||||
}
|
}
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
@ -46,7 +47,6 @@ const saveText = computed(
|
|||||||
const editStore = useEditStore()
|
const editStore = useEditStore()
|
||||||
const { schemaUpdateTime, schema, sessionId } = storeToRefs(editStore)
|
const { schemaUpdateTime, schema, sessionId } = storeToRefs(editStore)
|
||||||
|
|
||||||
|
|
||||||
const validate = () => {
|
const validate = () => {
|
||||||
let checked = true
|
let checked = true
|
||||||
let msg = ''
|
let msg = ''
|
||||||
@ -69,7 +69,7 @@ const validate = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const onSave = async () => {
|
const onSave = async () => {
|
||||||
const saveData = buildData(schema.value, sessionId.value);
|
const saveData = buildData(schema.value, sessionId.value)
|
||||||
if (!saveData.sessionId) {
|
if (!saveData.sessionId) {
|
||||||
ElMessage.error('sessionId有误')
|
ElMessage.error('sessionId有误')
|
||||||
return null
|
return null
|
||||||
@ -85,15 +85,6 @@ const onSave = async () => {
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
const seize = async () => {
|
|
||||||
const seizeRes: Record<string, any> = await seizeSession({ sessionId: sessionId.value })
|
|
||||||
if (seizeRes.code === 200) {
|
|
||||||
location.reload();
|
|
||||||
} else {
|
|
||||||
ElMessage.error('获取权限失败,请重试')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const timerHandle = ref<NodeJS.Timeout | number | null>(null)
|
const timerHandle = ref<NodeJS.Timeout | number | null>(null)
|
||||||
const triggerAutoSave = () => {
|
const triggerAutoSave = () => {
|
||||||
if (autoSaveStatus.value === 'saving') {
|
if (autoSaveStatus.value === 'saving') {
|
||||||
@ -147,7 +138,7 @@ const handleSave = async () => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const res: any = await onSave()
|
const res: any = await onSave()
|
||||||
if(!res) {
|
if (!res) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
@ -158,10 +149,10 @@ const handleSave = async () => {
|
|||||||
confirmButtonText: '刷新同步',
|
confirmButtonText: '刷新同步',
|
||||||
callback: (action: string) => {
|
callback: (action: string) => {
|
||||||
if (action === 'confirm') {
|
if (action === 'confirm') {
|
||||||
seize();
|
props.seize(sessionId.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
} else {
|
} else {
|
||||||
ElMessage.error(res.errmsg)
|
ElMessage.error(res.errmsg)
|
||||||
}
|
}
|
||||||
|
@ -141,20 +141,13 @@ export default {
|
|||||||
this.initCurOption()
|
this.initCurOption()
|
||||||
},
|
},
|
||||||
addOption(text = '选项', others = false, index = -1, fieldId) {
|
addOption(text = '选项', others = false, index = -1, fieldId) {
|
||||||
let addOne
|
let addOne = {
|
||||||
if (this.curOptions[0]) {
|
text: '',
|
||||||
addOne = _cloneDeep(this.curOptions[0])
|
hash: '',
|
||||||
} else {
|
others: false,
|
||||||
addOne = {
|
mustOthers: false,
|
||||||
text: '',
|
othersKey: '',
|
||||||
hash: '',
|
placeholderDesc: ''
|
||||||
others: false,
|
|
||||||
mustOthers: false,
|
|
||||||
othersKey: '',
|
|
||||||
placeholderDesc: '',
|
|
||||||
score: 0,
|
|
||||||
limit: ''
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for (const i in addOne) {
|
for (const i in addOne) {
|
||||||
if (i === 'others') {
|
if (i === 'others') {
|
||||||
|
@ -7,7 +7,7 @@ export default [
|
|||||||
{
|
{
|
||||||
title: '提交限制',
|
title: '提交限制',
|
||||||
key: 'limitConfig',
|
key: 'limitConfig',
|
||||||
formList: ['limit_tLimit', 'limit_breakAnswer', 'limit_backAnswer']
|
formList: ['limit_tLimit', 'limit_fillAnswer', 'limit_fillSubmitAnswer']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '作答限制',
|
title: '作答限制',
|
||||||
|
@ -22,21 +22,21 @@ export default {
|
|||||||
type: 'QuestionTimeHour',
|
type: 'QuestionTimeHour',
|
||||||
placement: 'top'
|
placement: 'top'
|
||||||
},
|
},
|
||||||
limit_breakAnswer: {
|
limit_fillAnswer: {
|
||||||
key: 'breakAnswer',
|
key: 'fillAnswer',
|
||||||
label: '允许断点续答',
|
label: '允许断点续答',
|
||||||
tip: '回填前一次作答中的内容(注:更换设备/浏览器/清除缓存/更改内容重新发布则此功能失效)',
|
tip: '回填前一次作答中的内容(注:更换设备/浏览器/清除缓存/更改内容重新发布则此功能失效)',
|
||||||
placement: 'top',
|
placement: 'top',
|
||||||
type: 'CustomedSwitch',
|
type: 'CustomedSwitch',
|
||||||
value: false,
|
value: false
|
||||||
},
|
},
|
||||||
limit_backAnswer: {
|
limit_fillSubmitAnswer: {
|
||||||
key: 'backAnswer',
|
key: 'fillSubmitAnswer',
|
||||||
label: '自动填充上次提交内容',
|
label: '自动填充上次提交内容',
|
||||||
tip: '回填前一次提交的内容(注:更换设备/浏览器/清除缓存/更改内容重新发布则此功能失效)',
|
tip: '回填前一次提交的内容(注:更换设备/浏览器/清除缓存/更改内容重新发布则此功能失效)',
|
||||||
placement: 'top',
|
placement: 'top',
|
||||||
type: 'CustomedSwitch',
|
type: 'CustomedSwitch',
|
||||||
value: false,
|
value: false
|
||||||
},
|
},
|
||||||
interview_pwd_switch: {
|
interview_pwd_switch: {
|
||||||
key: 'passwordSwitch',
|
key: 'passwordSwitch',
|
||||||
@ -112,5 +112,5 @@ export default {
|
|||||||
relyFunc: (data) => {
|
relyFunc: (data) => {
|
||||||
return data.whitelistType === 'MEMBER'
|
return data.whitelistType === 'MEMBER'
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
<el-form-item label="验证码" prop="captcha">
|
<el-form-item label="验证码" prop="captcha">
|
||||||
<div class="captcha-wrapper">
|
<div class="captcha-wrapper">
|
||||||
<el-input style="width: 280px" v-model="formData.captcha" size="large"></el-input>
|
<el-input style="width: 280px" v-model="formData.captcha" size="large"></el-input>
|
||||||
<div class="captcha-img" click="refreshCaptcha" v-html="captchaImgData"></div>
|
<div class="captcha-img" @click="refreshCaptcha" v-html="captchaImgData"></div>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import {
|
|||||||
set as _set,
|
set as _set,
|
||||||
isNumber as _isNumber
|
isNumber as _isNumber
|
||||||
} from 'lodash-es'
|
} from 'lodash-es'
|
||||||
|
import { ElMessageBox } from 'element-plus'
|
||||||
import { QUESTION_TYPE } from '@/common/typeEnum'
|
import { QUESTION_TYPE } from '@/common/typeEnum'
|
||||||
import { getQuestionByType } from '@/management/utils/index'
|
import { getQuestionByType } from '@/management/utils/index'
|
||||||
import { filterQuestionPreviewData } from '@/management/utils/index'
|
import { filterQuestionPreviewData } from '@/management/utils/index'
|
||||||
@ -24,7 +25,6 @@ import { CODE_MAP } from '../api/base'
|
|||||||
import { RuleBuild } from '@/common/logicEngine/RuleBuild'
|
import { RuleBuild } from '@/common/logicEngine/RuleBuild'
|
||||||
import { useShowLogicInfo } from '@/management/hooks/useShowLogicInfo'
|
import { useShowLogicInfo } from '@/management/hooks/useShowLogicInfo'
|
||||||
import { useJumpLogicInfo } from '@/management/hooks/useJumpLogicInfo'
|
import { useJumpLogicInfo } from '@/management/hooks/useJumpLogicInfo'
|
||||||
import { ElMessageBox } from 'element-plus'
|
|
||||||
|
|
||||||
const innerMetaConfig = {
|
const innerMetaConfig = {
|
||||||
submit: {
|
submit: {
|
||||||
@ -69,7 +69,6 @@ function useInitializeSchema(surveyId: Ref<string>, initializeSchemaCallBack: ()
|
|||||||
begTime: '',
|
begTime: '',
|
||||||
endTime: '',
|
endTime: '',
|
||||||
language: 'chinese',
|
language: 'chinese',
|
||||||
showVoteProcess: 'allow',
|
|
||||||
tLimit: 0,
|
tLimit: 0,
|
||||||
answerBegTime: '',
|
answerBegTime: '',
|
||||||
answerEndTime: '',
|
answerEndTime: '',
|
||||||
@ -107,6 +106,21 @@ function useInitializeSchema(surveyId: Ref<string>, initializeSchemaCallBack: ()
|
|||||||
schema.pageConf = codeData.pageConf
|
schema.pageConf = codeData.pageConf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const sessionId = ref('')
|
||||||
|
async function initSessionId() {
|
||||||
|
const sessionIdKey = `${surveyId.value}_sessionId`
|
||||||
|
const localSessionId = sessionStorage.getItem(sessionIdKey)
|
||||||
|
if (localSessionId) {
|
||||||
|
sessionId.value = localSessionId
|
||||||
|
} else {
|
||||||
|
const res: Record<string, any> = await getSessionId({ surveyId: surveyId.value })
|
||||||
|
if (res.code === 200) {
|
||||||
|
sessionId.value = res.data.sessionId
|
||||||
|
sessionStorage.setItem(sessionIdKey, sessionId.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function getSchemaFromRemote() {
|
async function getSchemaFromRemote() {
|
||||||
const res: any = await getSurveyById(surveyId.value)
|
const res: any = await getSurveyById(surveyId.value)
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
@ -149,10 +163,11 @@ function useInitializeSchema(surveyId: Ref<string>, initializeSchemaCallBack: ()
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
schema,
|
schema,
|
||||||
initSchema,
|
|
||||||
getSchemaFromRemote,
|
getSchemaFromRemote,
|
||||||
showLogicEngine,
|
showLogicEngine,
|
||||||
jumpLogicEngine,
|
jumpLogicEngine,
|
||||||
|
sessionId,
|
||||||
|
initSessionId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -479,7 +494,6 @@ function useLogicEngine(schema: any) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type IBannerItem = {
|
type IBannerItem = {
|
||||||
name: string
|
name: string
|
||||||
key: string
|
key: string
|
||||||
@ -487,37 +501,54 @@ type IBannerItem = {
|
|||||||
}
|
}
|
||||||
type IBannerList = Record<string, IBannerItem>
|
type IBannerList = Record<string, IBannerItem>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export const useEditStore = defineStore('edit', () => {
|
export const useEditStore = defineStore('edit', () => {
|
||||||
const surveyId = ref('')
|
|
||||||
const bannerList: Ref<IBannerList> = ref({})
|
const bannerList: Ref<IBannerList> = ref({})
|
||||||
const cooperPermissions = ref(Object.values(SurveyPermissions))
|
const fetchBannerData = async () => {
|
||||||
const schemaUpdateTime = ref(Date.now())
|
const res: any = await getBannerData()
|
||||||
|
if (res.code === CODE_MAP.SUCCESS) {
|
||||||
|
bannerList.value = res.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const cooperPermissions = ref(Object.values(SurveyPermissions))
|
||||||
|
const fetchCooperPermissions = async (id: string) => {
|
||||||
|
const res: any = await getCollaboratorPermissions(id)
|
||||||
|
if (res.code === CODE_MAP.SUCCESS) {
|
||||||
|
cooperPermissions.value = res.data.permissions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const schemaUpdateTime = ref(Date.now())
|
||||||
|
function updateTime() {
|
||||||
|
schemaUpdateTime.value = Date.now()
|
||||||
|
}
|
||||||
|
|
||||||
|
const surveyId = ref('')
|
||||||
function setSurveyId(id: string) {
|
function setSurveyId(id: string) {
|
||||||
surveyId.value = id
|
surveyId.value = id
|
||||||
}
|
}
|
||||||
|
|
||||||
const { schema, initSchema, getSchemaFromRemote, showLogicEngine, jumpLogicEngine } =
|
// 初始化schem相关
|
||||||
useInitializeSchema(surveyId, () => {
|
const {
|
||||||
editGlobalBaseConf.initCounts()
|
schema,
|
||||||
|
sessionId,
|
||||||
|
initSessionId,
|
||||||
|
getSchemaFromRemote,
|
||||||
|
showLogicEngine,
|
||||||
|
jumpLogicEngine
|
||||||
|
} = useInitializeSchema(surveyId, () => {
|
||||||
|
editGlobalBaseConf.initCounts()
|
||||||
|
})
|
||||||
|
|
||||||
|
function changeSchema({ key, value }: { key: string; value: any }) {
|
||||||
|
_set(schema, key, value)
|
||||||
|
updateTime()
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeThemePreset(presets: any) {
|
||||||
|
Object.keys(presets).forEach((key) => {
|
||||||
|
_set(schema, key, presets[key])
|
||||||
})
|
})
|
||||||
|
|
||||||
const sessionId = ref('')
|
|
||||||
|
|
||||||
async function initSessionId() {
|
|
||||||
const sessionIdKey = `${surveyId.value}_sessionId`;
|
|
||||||
const localSessionId = sessionStorage.getItem(sessionIdKey)
|
|
||||||
if (localSessionId) {
|
|
||||||
sessionId.value = localSessionId
|
|
||||||
} else {
|
|
||||||
const res: Record<string, any> = await getSessionId({ surveyId: surveyId.value })
|
|
||||||
if (res.code === 200) {
|
|
||||||
sessionId.value = res.data.sessionId
|
|
||||||
sessionStorage.setItem(sessionIdKey, sessionId.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const questionDataList = toRef(schema, 'questionDataList')
|
const questionDataList = toRef(schema, 'questionDataList')
|
||||||
@ -527,86 +558,14 @@ export const useEditStore = defineStore('edit', () => {
|
|||||||
schema.questionDataList = data
|
schema.questionDataList = data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const createNewQuestion = ({ type }: { type: QUESTION_TYPE }) => {
|
||||||
const fetchBannerData = async () => {
|
const fields = questionDataList.value.map((item: any) => item.field)
|
||||||
const res: any = await getBannerData()
|
const newQuestion = getQuestionByType(type, fields)
|
||||||
if (res.code === CODE_MAP.SUCCESS) {
|
newQuestion.title = newQuestion.title = `标题${newQuestionIndex.value + 1}`
|
||||||
bannerList.value = res.data
|
if (type === QUESTION_TYPE.VOTE) {
|
||||||
|
newQuestion.innerType = QUESTION_TYPE.RADIO
|
||||||
}
|
}
|
||||||
}
|
return newQuestion
|
||||||
|
|
||||||
const fetchCooperPermissions = async (id: string) => {
|
|
||||||
const res: any = await getCollaboratorPermissions(id)
|
|
||||||
if (res.code === CODE_MAP.SUCCESS) {
|
|
||||||
cooperPermissions.value = res.data.permissions
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// const { showLogicEngine, initShowLogicEngine, jumpLogicEngine, initJumpLogicEngine } = useLogicEngine(schema)
|
|
||||||
const {
|
|
||||||
currentEditOne,
|
|
||||||
currentEditKey,
|
|
||||||
currentEditStatus,
|
|
||||||
moduleConfig,
|
|
||||||
formConfigList,
|
|
||||||
currentEditMeta,
|
|
||||||
setCurrentEditOne,
|
|
||||||
changeCurrentEditStatus
|
|
||||||
} = useCurrentEdit({ schema, questionDataList })
|
|
||||||
|
|
||||||
async function init() {
|
|
||||||
const { metaData } = schema
|
|
||||||
if (!metaData || (metaData as any)?._id !== surveyId.value) {
|
|
||||||
await getSchemaFromRemote()
|
|
||||||
await initSessionId()
|
|
||||||
}
|
|
||||||
currentEditOne.value = null
|
|
||||||
currentEditStatus.value = 'Success'
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateTime() {
|
|
||||||
schemaUpdateTime.value = Date.now()
|
|
||||||
}
|
|
||||||
|
|
||||||
const {
|
|
||||||
pageEditOne,
|
|
||||||
pageConf,
|
|
||||||
isFinallyPage,
|
|
||||||
pageCount,
|
|
||||||
pageQuestionData,
|
|
||||||
getSorter,
|
|
||||||
updatePageEditOne,
|
|
||||||
deletePage,
|
|
||||||
pageOperations,
|
|
||||||
addPage,
|
|
||||||
getPageQuestionData,
|
|
||||||
copyPage,
|
|
||||||
swapArrayRanges,
|
|
||||||
setPage
|
|
||||||
} = usePageEdit({ schema, questionDataList }, updateTime)
|
|
||||||
|
|
||||||
const { copyQuestion, addQuestion, deleteQuestion, moveQuestion } = useQuestionDataListOperations(
|
|
||||||
{
|
|
||||||
questionDataList,
|
|
||||||
updateTime,
|
|
||||||
pageOperations,
|
|
||||||
updateCounts: editGlobalBaseConf.updateCounts
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
function moveQuestionDataList(data: any) {
|
|
||||||
const { startIndex, endIndex } = getSorter()
|
|
||||||
const newData = [
|
|
||||||
...questionDataList.value.slice(0, startIndex),
|
|
||||||
...data,
|
|
||||||
...questionDataList.value.slice(endIndex)
|
|
||||||
]
|
|
||||||
const countTotal: number = (schema.pageConf as Array<number>).reduce(
|
|
||||||
(v: number, i: number) => v + i
|
|
||||||
)
|
|
||||||
if (countTotal != newData.length) {
|
|
||||||
schema.pageConf[pageEditOne.value - 1] = (schema.pageConf[pageEditOne.value - 1] + 1) as never
|
|
||||||
}
|
|
||||||
setQuestionDataList(newData)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const compareQuestionSeq = (val: Array<any>) => {
|
const compareQuestionSeq = (val: Array<any>) => {
|
||||||
@ -644,25 +603,70 @@ export const useEditStore = defineStore('edit', () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const createNewQuestion = ({ type }: { type: QUESTION_TYPE }) => {
|
// 当前编辑题目
|
||||||
const fields = questionDataList.value.map((item: any) => item.field)
|
const {
|
||||||
const newQuestion = getQuestionByType(type, fields)
|
currentEditOne,
|
||||||
newQuestion.title = newQuestion.title = `标题${newQuestionIndex.value + 1}`
|
currentEditKey,
|
||||||
if (type === QUESTION_TYPE.VOTE) {
|
currentEditStatus,
|
||||||
newQuestion.innerType = QUESTION_TYPE.RADIO
|
moduleConfig,
|
||||||
|
formConfigList,
|
||||||
|
currentEditMeta,
|
||||||
|
setCurrentEditOne,
|
||||||
|
changeCurrentEditStatus
|
||||||
|
} = useCurrentEdit({ schema, questionDataList })
|
||||||
|
|
||||||
|
// 初始化问卷
|
||||||
|
async function init() {
|
||||||
|
const { metaData } = schema
|
||||||
|
if (!metaData || (metaData as any)?._id !== surveyId.value) {
|
||||||
|
await Promise.all([getSchemaFromRemote(), initSessionId()])
|
||||||
}
|
}
|
||||||
return newQuestion
|
currentEditOne.value = null
|
||||||
|
currentEditStatus.value = 'Success'
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeSchema({ key, value }: { key: string; value: any }) {
|
// 分页相关
|
||||||
_set(schema, key, value)
|
const {
|
||||||
updateTime()
|
pageEditOne,
|
||||||
}
|
pageConf,
|
||||||
|
isFinallyPage,
|
||||||
|
pageCount,
|
||||||
|
pageQuestionData,
|
||||||
|
getSorter,
|
||||||
|
updatePageEditOne,
|
||||||
|
deletePage,
|
||||||
|
pageOperations,
|
||||||
|
addPage,
|
||||||
|
getPageQuestionData,
|
||||||
|
copyPage,
|
||||||
|
swapArrayRanges,
|
||||||
|
setPage
|
||||||
|
} = usePageEdit({ schema, questionDataList }, updateTime)
|
||||||
|
|
||||||
function changeThemePreset(presets: any) {
|
// 问卷列表相关操作
|
||||||
Object.keys(presets).forEach((key) => {
|
const { copyQuestion, addQuestion, deleteQuestion, moveQuestion } = useQuestionDataListOperations(
|
||||||
_set(schema, key, presets[key])
|
{
|
||||||
})
|
questionDataList,
|
||||||
|
updateTime,
|
||||||
|
pageOperations,
|
||||||
|
updateCounts: editGlobalBaseConf.updateCounts
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
function moveQuestionDataList(data: any) {
|
||||||
|
const { startIndex, endIndex } = getSorter()
|
||||||
|
const newData = [
|
||||||
|
...questionDataList.value.slice(0, startIndex),
|
||||||
|
...data,
|
||||||
|
...questionDataList.value.slice(endIndex)
|
||||||
|
]
|
||||||
|
const countTotal: number = (schema.pageConf as Array<number>).reduce(
|
||||||
|
(v: number, i: number) => v + i
|
||||||
|
)
|
||||||
|
if (countTotal != newData.length) {
|
||||||
|
schema.pageConf[pageEditOne.value - 1] = (schema.pageConf[pageEditOne.value - 1] + 1) as never
|
||||||
|
}
|
||||||
|
setQuestionDataList(newData)
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -670,7 +674,6 @@ export const useEditStore = defineStore('edit', () => {
|
|||||||
surveyId,
|
surveyId,
|
||||||
sessionId,
|
sessionId,
|
||||||
setSurveyId,
|
setSurveyId,
|
||||||
initSessionId,
|
|
||||||
bannerList,
|
bannerList,
|
||||||
fetchBannerData,
|
fetchBannerData,
|
||||||
cooperPermissions,
|
cooperPermissions,
|
||||||
@ -703,7 +706,6 @@ export const useEditStore = defineStore('edit', () => {
|
|||||||
setQuestionDataList,
|
setQuestionDataList,
|
||||||
moveQuestionDataList,
|
moveQuestionDataList,
|
||||||
init,
|
init,
|
||||||
initSchema,
|
|
||||||
getSchemaFromRemote,
|
getSchemaFromRemote,
|
||||||
copyQuestion,
|
copyQuestion,
|
||||||
addQuestion,
|
addQuestion,
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
import localstorage from '@/common/localstorage'
|
||||||
|
|
||||||
type IUserInfo = {
|
type IUserInfo = {
|
||||||
username: string
|
username: string
|
||||||
token: string
|
token: string
|
||||||
@ -17,12 +19,12 @@ export const useUserStore = defineStore('user', () => {
|
|||||||
const initialized = ref(false)
|
const initialized = ref(false)
|
||||||
|
|
||||||
const init = () => {
|
const init = () => {
|
||||||
const localData = localStorage.getItem(USER_INFO_KEY)
|
const localData = localstorage.getItem(USER_INFO_KEY)
|
||||||
if (localData) {
|
if (localData) {
|
||||||
try {
|
try {
|
||||||
const { userInfo: info, loginTime: time } = JSON.parse(localData)
|
const { userInfo: info, loginTime: time } = localData as any
|
||||||
if (Date.now() - time > 7 * 3600000) {
|
if (Date.now() - time > 7 * 3600000) {
|
||||||
localStorage.removeItem(USER_INFO_KEY)
|
localstorage.removeItem(USER_INFO_KEY)
|
||||||
} else {
|
} else {
|
||||||
login(info)
|
login(info)
|
||||||
}
|
}
|
||||||
@ -36,18 +38,15 @@ export const useUserStore = defineStore('user', () => {
|
|||||||
userInfo.value = data
|
userInfo.value = data
|
||||||
hasLogined.value = true
|
hasLogined.value = true
|
||||||
loginTime.value = Date.now()
|
loginTime.value = Date.now()
|
||||||
localStorage.setItem(
|
localstorage.setItem(USER_INFO_KEY, {
|
||||||
USER_INFO_KEY,
|
userInfo: data,
|
||||||
JSON.stringify({
|
loginTime: loginTime
|
||||||
userInfo: data,
|
})
|
||||||
loginTime: loginTime
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
const logout = () => {
|
const logout = () => {
|
||||||
userInfo.value = null
|
userInfo.value = null
|
||||||
hasLogined.value = false
|
hasLogined.value = false
|
||||||
localStorage.removeItem(USER_INFO_KEY)
|
localstorage.removeItem(USER_INFO_KEY)
|
||||||
}
|
}
|
||||||
|
|
||||||
return { userInfo, hasLogined, loginTime, initialized, init, login, logout }
|
return { userInfo, hasLogined, loginTime, initialized, init, login, logout }
|
||||||
|
@ -19,7 +19,6 @@ export function getRandom(len) {
|
|||||||
|
|
||||||
const optionListItem = [
|
const optionListItem = [
|
||||||
'text',
|
'text',
|
||||||
'imageUrl',
|
|
||||||
'others',
|
'others',
|
||||||
'mustOthers',
|
'mustOthers',
|
||||||
'limit',
|
'limit',
|
||||||
|
@ -25,14 +25,12 @@
|
|||||||
padding: 0 0.2rem !important;
|
padding: 0 0.2rem !important;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// .choice-content, .choice-item {
|
// .choice-content, .choice-item {
|
||||||
// width: 100%;
|
// width: 100%;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
&.vertical {
|
&.vertical {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
.choice-outer {
|
.choice-outer {
|
||||||
|
@ -54,7 +54,6 @@ const meta = {
|
|||||||
defaultValue: [
|
defaultValue: [
|
||||||
{
|
{
|
||||||
text: '对',
|
text: '对',
|
||||||
imageUrl: '',
|
|
||||||
others: false,
|
others: false,
|
||||||
mustOthers: false,
|
mustOthers: false,
|
||||||
othersKey: '',
|
othersKey: '',
|
||||||
@ -63,7 +62,6 @@ const meta = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: '错',
|
text: '错',
|
||||||
imageUrl: '',
|
|
||||||
others: false,
|
others: false,
|
||||||
mustOthers: false,
|
mustOthers: false,
|
||||||
othersKey: '',
|
othersKey: '',
|
||||||
@ -79,29 +77,32 @@ const meta = {
|
|||||||
defaultValue: 'vertical'
|
defaultValue: 'vertical'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
formConfig: [basicConfig, {
|
formConfig: [
|
||||||
name: 'optionConfig',
|
basicConfig,
|
||||||
title: '选项配置',
|
{
|
||||||
type: 'Customed',
|
name: 'optionConfig',
|
||||||
content: [
|
title: '选项配置',
|
||||||
{
|
type: 'Customed',
|
||||||
label: '排列方式',
|
content: [
|
||||||
type: 'RadioGroup',
|
{
|
||||||
key: 'layout',
|
label: '排列方式',
|
||||||
value: 'vertical',
|
type: 'RadioGroup',
|
||||||
options: [
|
key: 'layout',
|
||||||
{
|
value: 'vertical',
|
||||||
label: '竖排',
|
options: [
|
||||||
value: 'vertical'
|
{
|
||||||
},
|
label: '竖排',
|
||||||
{
|
value: 'vertical'
|
||||||
label: '横排',
|
},
|
||||||
value: 'horizontal'
|
{
|
||||||
},
|
label: '横排',
|
||||||
]
|
value: 'horizontal'
|
||||||
},
|
}
|
||||||
]
|
]
|
||||||
}],
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
editConfigure: {
|
editConfigure: {
|
||||||
optionEdit: {
|
optionEdit: {
|
||||||
show: false
|
show: false
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { computed, defineComponent, shallowRef, defineAsyncComponent, watch } from 'vue'
|
import { computed, defineComponent, shallowRef, defineAsyncComponent } from 'vue'
|
||||||
import { includes } from 'lodash-es'
|
import { includes } from 'lodash-es'
|
||||||
|
|
||||||
import BaseChoice from '../BaseChoice'
|
import BaseChoice from '../BaseChoice'
|
||||||
|
@ -53,7 +53,6 @@ const meta = {
|
|||||||
defaultValue: [
|
defaultValue: [
|
||||||
{
|
{
|
||||||
text: '选项1',
|
text: '选项1',
|
||||||
imageUrl: '',
|
|
||||||
others: false,
|
others: false,
|
||||||
mustOthers: false,
|
mustOthers: false,
|
||||||
othersKey: '',
|
othersKey: '',
|
||||||
@ -62,7 +61,6 @@ const meta = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: '选项2',
|
text: '选项2',
|
||||||
imageUrl: '',
|
|
||||||
others: false,
|
others: false,
|
||||||
mustOthers: false,
|
mustOthers: false,
|
||||||
othersKey: '',
|
othersKey: '',
|
||||||
|
@ -12,7 +12,7 @@ function useOptionBase(options) {
|
|||||||
others: false,
|
others: false,
|
||||||
mustOthers: false,
|
mustOthers: false,
|
||||||
othersKey: '',
|
othersKey: '',
|
||||||
placeholderDesc: '',
|
placeholderDesc: ''
|
||||||
}
|
}
|
||||||
if (typeof text !== 'string') {
|
if (typeof text !== 'string') {
|
||||||
text = '选项'
|
text = '选项'
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { defineComponent, shallowRef, watch, defineAsyncComponent } from 'vue'
|
import { defineComponent, shallowRef, defineAsyncComponent } from 'vue'
|
||||||
import BaseChoice from '../BaseChoice'
|
import BaseChoice from '../BaseChoice'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -54,7 +54,6 @@ const meta = {
|
|||||||
defaultValue: [
|
defaultValue: [
|
||||||
{
|
{
|
||||||
text: '选项1',
|
text: '选项1',
|
||||||
imageUrl: '',
|
|
||||||
others: false,
|
others: false,
|
||||||
mustOthers: false,
|
mustOthers: false,
|
||||||
othersKey: '',
|
othersKey: '',
|
||||||
@ -63,7 +62,6 @@ const meta = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: '选项2',
|
text: '选项2',
|
||||||
imageUrl: '',
|
|
||||||
others: false,
|
others: false,
|
||||||
mustOthers: false,
|
mustOthers: false,
|
||||||
othersKey: '',
|
othersKey: '',
|
||||||
|
@ -48,9 +48,9 @@ export default defineComponent({
|
|||||||
|
|
||||||
watch(status, (v) => {
|
watch(status, (v) => {
|
||||||
if (v === 'edit') {
|
if (v === 'edit') {
|
||||||
document.addEventListener('click', handleDocumentClick, {capture: true})
|
document.addEventListener('click', handleDocumentClick, { capture: true })
|
||||||
} else {
|
} else {
|
||||||
document.removeEventListener('click', handleDocumentClick, {capture: true})
|
document.removeEventListener('click', handleDocumentClick, { capture: true })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -54,7 +54,6 @@ const meta = {
|
|||||||
defaultValue: [
|
defaultValue: [
|
||||||
{
|
{
|
||||||
text: '选项1',
|
text: '选项1',
|
||||||
imageUrl: '',
|
|
||||||
others: false,
|
others: false,
|
||||||
mustOthers: false,
|
mustOthers: false,
|
||||||
othersKey: '',
|
othersKey: '',
|
||||||
@ -63,7 +62,6 @@ const meta = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: '选项2',
|
text: '选项2',
|
||||||
imageUrl: '',
|
|
||||||
others: false,
|
others: false,
|
||||||
mustOthers: false,
|
mustOthers: false,
|
||||||
othersKey: '',
|
othersKey: '',
|
||||||
@ -120,7 +118,9 @@ const meta = {
|
|||||||
key: 'minNum',
|
key: 'minNum',
|
||||||
value: '',
|
value: '',
|
||||||
min: 0,
|
min: 0,
|
||||||
max: moduleConfig => { return moduleConfig?.maxNum || 0 },
|
max: (moduleConfig) => {
|
||||||
|
return moduleConfig?.maxNum || 0
|
||||||
|
},
|
||||||
contentClass: 'input-number-config'
|
contentClass: 'input-number-config'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -128,8 +128,12 @@ const meta = {
|
|||||||
type: 'InputNumber',
|
type: 'InputNumber',
|
||||||
key: 'maxNum',
|
key: 'maxNum',
|
||||||
value: '',
|
value: '',
|
||||||
min: moduleConfig => { return moduleConfig?.minNum || 0 },
|
min: (moduleConfig) => {
|
||||||
max: moduleConfig => { return moduleConfig?.options?.length || 0 },
|
return moduleConfig?.minNum || 0
|
||||||
|
},
|
||||||
|
max: (moduleConfig) => {
|
||||||
|
return moduleConfig?.options?.length || 0
|
||||||
|
},
|
||||||
contentClass: 'input-number-config'
|
contentClass: 'input-number-config'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -13,7 +13,6 @@ 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
|
||||||
@ -66,9 +65,12 @@ const handleInputChange = (value: number) => {
|
|||||||
|
|
||||||
emit(FORM_CHANGE_EVENT_KEY, { key, value })
|
emit(FORM_CHANGE_EVENT_KEY, { key, value })
|
||||||
}
|
}
|
||||||
watch(() => props.moduleConfig, (newVal) => {
|
watch(
|
||||||
myModuleConfig.value = newVal
|
() => props.moduleConfig,
|
||||||
})
|
(newVal) => {
|
||||||
|
myModuleConfig.value = newVal
|
||||||
|
}
|
||||||
|
)
|
||||||
watch(
|
watch(
|
||||||
() => props.formConfig.value,
|
() => props.formConfig.value,
|
||||||
(newVal) => {
|
(newVal) => {
|
||||||
|
@ -1,79 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="mask" v-show="visible">
|
|
||||||
<div class="box">
|
|
||||||
<div class="title">{{ title }}</div>
|
|
||||||
<div class="btn-box">
|
|
||||||
<div class="btn cancel" @click="handleCancel">{{ cancelBtnText }}</div>
|
|
||||||
<div class="btn confirm" @click="handleConfirm">{{ confirmBtnText }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script setup lang="ts">
|
|
||||||
interface Props {
|
|
||||||
visible?: boolean
|
|
||||||
cancelBtnText?: string
|
|
||||||
confirmBtnText?: string
|
|
||||||
title?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Emit {
|
|
||||||
(ev: 'confirm', callback: () => void): void
|
|
||||||
(ev: 'cancel', callback: () => void): void
|
|
||||||
(ev: 'close'): void
|
|
||||||
}
|
|
||||||
|
|
||||||
const emit = defineEmits<Emit>()
|
|
||||||
|
|
||||||
withDefaults(defineProps<Props>(), {
|
|
||||||
visible: false,
|
|
||||||
cancelBtnText: '取消',
|
|
||||||
confirmBtnText: '确定',
|
|
||||||
title: ''
|
|
||||||
})
|
|
||||||
|
|
||||||
const handleConfirm = () => {
|
|
||||||
emit('confirm', () => {
|
|
||||||
emit('close')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleCancel = () => {
|
|
||||||
emit('cancel', () => {
|
|
||||||
emit('close')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
@import url('../styles/dialog.scss');
|
|
||||||
|
|
||||||
.btn-box {
|
|
||||||
padding: 20px 0 0;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
|
|
||||||
.btn {
|
|
||||||
width: 48%;
|
|
||||||
font-size: 0.28rem;
|
|
||||||
border-radius: 0.04rem;
|
|
||||||
text-align: center;
|
|
||||||
padding: 0.16rem 0;
|
|
||||||
line-height: 0.4rem;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&.cancel {
|
|
||||||
background: #fff;
|
|
||||||
color: #92949d;
|
|
||||||
border: 1px solid #e3e4e8;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.confirm {
|
|
||||||
background-color: #4a4c5b;
|
|
||||||
border: 1px solid #4a4c5b;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -9,17 +9,18 @@
|
|||||||
></QuestionRuleContainer>
|
></QuestionRuleContainer>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { unref, computed, watch } from 'vue'
|
import { unref, computed, watch, ref } from 'vue'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
import QuestionRuleContainer from '../../materials/questions/QuestionRuleContainer'
|
import QuestionRuleContainer from '../../materials/questions/QuestionRuleContainer'
|
||||||
import { useVoteMap } from '@/render/hooks/useVoteMap'
|
import { useVoteMap } from '@/render/hooks/useVoteMap'
|
||||||
import { useShowOthers } from '@/render/hooks/useShowOthers'
|
import { useShowOthers } from '@/render/hooks/useShowOthers'
|
||||||
import { useShowInput } from '@/render/hooks/useShowInput'
|
import { useShowInput } from '@/render/hooks/useShowInput'
|
||||||
import { cloneDeep } from 'lodash-es'
|
import { debounce, cloneDeep } from 'lodash-es'
|
||||||
import { useQuestionStore } from '../stores/question'
|
import { useQuestionStore } from '../stores/question'
|
||||||
import { useSurveyStore } from '../stores/survey'
|
import { useSurveyStore } from '../stores/survey'
|
||||||
|
import { FORMDATA_SUFFIX, SUBMIT_FLAG } from '../utils/constant'
|
||||||
import { NORMAL_CHOICES, RATES, QUESTION_TYPE } from '@/common/typeEnum.ts'
|
import { NORMAL_CHOICES, RATES, QUESTION_TYPE } from '@/common/typeEnum.ts'
|
||||||
|
import localstorage from '@/common/localstorage'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
indexNumber: {
|
indexNumber: {
|
||||||
@ -46,7 +47,7 @@ const { changeField, changeIndex, needHideFields } = storeToRefs(questionStore)
|
|||||||
const questionConfig = computed(() => {
|
const questionConfig = computed(() => {
|
||||||
let moduleConfig = props.moduleConfig
|
let moduleConfig = props.moduleConfig
|
||||||
const { type, field, options = [], ...rest } = cloneDeep(moduleConfig)
|
const { type, field, options = [], ...rest } = cloneDeep(moduleConfig)
|
||||||
// console.log(field,'这里依赖的formValue,所以change时会触发重新计算')
|
|
||||||
let alloptions = options
|
let alloptions = options
|
||||||
|
|
||||||
if (type === QUESTION_TYPE.VOTE) {
|
if (type === QUESTION_TYPE.VOTE) {
|
||||||
@ -126,14 +127,28 @@ const handleChange = (data) => {
|
|||||||
if (props.moduleConfig.type === QUESTION_TYPE.VOTE) {
|
if (props.moduleConfig.type === QUESTION_TYPE.VOTE) {
|
||||||
questionStore.updateVoteData(data)
|
questionStore.updateVoteData(data)
|
||||||
}
|
}
|
||||||
// 断点续答的的数据缓存
|
|
||||||
localStorageBack()
|
|
||||||
processJumpSkip()
|
processJumpSkip()
|
||||||
|
valueTemp.value = data.value
|
||||||
|
debounceStorageSave()
|
||||||
|
}
|
||||||
|
const valueTemp = ref()
|
||||||
|
const handleInput = (e) => {
|
||||||
|
valueTemp.value = e.target.value
|
||||||
|
debounceStorageSave()
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleInput = () => {
|
const debounceStorageSave = debounce(() => {
|
||||||
localStorageBack()
|
let data = {
|
||||||
}
|
key: props.moduleConfig.field,
|
||||||
|
value: valueTemp.value
|
||||||
|
}
|
||||||
|
const formData = cloneDeep(formValues.value)
|
||||||
|
let { key, value } = data
|
||||||
|
if (key in formData) {
|
||||||
|
formData[key] = value
|
||||||
|
}
|
||||||
|
localStorageSave(formData)
|
||||||
|
}, 500)
|
||||||
|
|
||||||
const processJumpSkip = () => {
|
const processJumpSkip = () => {
|
||||||
const targetResult = surveyStore.jumpLogicEngine
|
const targetResult = surveyStore.jumpLogicEngine
|
||||||
@ -175,12 +190,9 @@ const processJumpSkip = () => {
|
|||||||
.map((item) => item.field)
|
.map((item) => item.field)
|
||||||
questionStore.addNeedHideFields(skipKey)
|
questionStore.addNeedHideFields(skipKey)
|
||||||
}
|
}
|
||||||
const localStorageBack = () => {
|
const localStorageSave = (formData) => {
|
||||||
var formData = Object.assign({}, surveyStore.formValues)
|
localstorage.removeItem(surveyStore.surveyPath + FORMDATA_SUFFIX)
|
||||||
|
localstorage.setItem(surveyStore.surveyPath + FORMDATA_SUFFIX, formData)
|
||||||
//浏览器存储
|
localstorage.setItem(SUBMIT_FLAG, false)
|
||||||
localStorage.removeItem(surveyStore.surveyPath + '_questionData')
|
|
||||||
localStorage.setItem(surveyStore.surveyPath + '_questionData', JSON.stringify(formData))
|
|
||||||
localStorage.setItem('isSubmit', JSON.stringify(false))
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -4,15 +4,17 @@ export const useQuestionInfo = (field: string) => {
|
|||||||
const questionstore = useQuestionStore()
|
const questionstore = useQuestionStore()
|
||||||
|
|
||||||
const questionTitle = cleanRichText(questionstore.questionData[field]?.title)
|
const questionTitle = cleanRichText(questionstore.questionData[field]?.title)
|
||||||
const getOptionTitle = (value:any) => {
|
const getOptionTitle = (value: any) => {
|
||||||
const options = questionstore.questionData[field]?.options || []
|
const options = questionstore.questionData[field]?.options || []
|
||||||
if (value instanceof Array) {
|
if (value instanceof Array) {
|
||||||
return options
|
return options
|
||||||
.filter((item:any) => value.includes(item.hash))
|
.filter((item: any) => value.includes(item.hash))
|
||||||
.map((item:any) => cleanRichText(item.text))
|
.map((item: any) => cleanRichText(item.text))
|
||||||
} else {
|
} else {
|
||||||
return options.filter((item:any) => item.hash === value).map((item:any) => cleanRichText(item.text))
|
return options
|
||||||
}
|
.filter((item: any) => item.hash === value)
|
||||||
|
.map((item: any) => cleanRichText(item.text))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return { questionTitle, getOptionTitle }
|
return { questionTitle, getOptionTitle }
|
||||||
}
|
}
|
||||||
|
@ -9,9 +9,9 @@
|
|||||||
<script>
|
<script>
|
||||||
;(function () {
|
;(function () {
|
||||||
function resetRemUnit() {
|
function resetRemUnit() {
|
||||||
var PC_W = 750
|
const PC_W = 750
|
||||||
var docEl = window.document.documentElement
|
let docEl = window.document.documentElement
|
||||||
var width = docEl.getBoundingClientRect().width || 375
|
let width = docEl.getBoundingClientRect().width || 375
|
||||||
|
|
||||||
if (!/Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent)) {
|
if (!/Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent)) {
|
||||||
width = width < PC_W ? width : PC_W
|
width = width < PC_W ? width : PC_W
|
||||||
@ -20,15 +20,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var f = Math.min(width / 7.5, 50)
|
const f = Math.min(width / 7.5, 50)
|
||||||
docEl.style.fontSize = f + 'px'
|
docEl.style.fontSize = f + 'px'
|
||||||
|
|
||||||
var d = window.document.createElement('div')
|
let d = window.document.createElement('div')
|
||||||
d.style.width = '1rem'
|
d.style.width = '1rem'
|
||||||
d.style.display = 'none'
|
d.style.display = 'none'
|
||||||
var head = window.document.getElementsByTagName('head')[0]
|
let head = window.document.getElementsByTagName('head')[0]
|
||||||
head.appendChild(d)
|
head.appendChild(d)
|
||||||
var realf = parseFloat(window.getComputedStyle(d, null).getPropertyValue('width'))
|
const realf = parseFloat(window.getComputedStyle(d, null).getPropertyValue('width'))
|
||||||
|
|
||||||
if (f !== realf) {
|
if (f !== realf) {
|
||||||
docEl.style.fontSize = f * (f / realf) + 'px'
|
docEl.style.fontSize = f * (f / realf) + 'px'
|
||||||
|
@ -38,7 +38,8 @@ import encrypt from '../utils/encrypt'
|
|||||||
|
|
||||||
import useCommandComponent from '../hooks/useCommandComponent'
|
import useCommandComponent from '../hooks/useCommandComponent'
|
||||||
import { getPublishedSurveyInfo, getPreviewSchema } from '../api/survey'
|
import { getPublishedSurveyInfo, getPreviewSchema } from '../api/survey'
|
||||||
import { useQuestionInfo } from '../hooks/useQuestionInfo'
|
import { FORMDATA_SUFFIX, SUBMIT_FLAG } from '@/render/utils/constant'
|
||||||
|
import localstorage from '@/common/localstorage'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
questionInfo?: any
|
questionInfo?: any
|
||||||
@ -151,13 +152,13 @@ const normalizationRequestBody = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//浏览器缓存数据
|
//浏览器缓存数据
|
||||||
localStorage.removeItem(surveyPath.value + '_questionData')
|
localstorage.removeItem(surveyPath.value + FORMDATA_SUFFIX)
|
||||||
localStorage.removeItem('isSubmit')
|
localstorage.removeItem(SUBMIT_FLAG)
|
||||||
//数据加密
|
//数据加密
|
||||||
var formData: Record<string, any> = Object.assign({}, surveyStore.formValues)
|
let formData: Record<string, any> = Object.assign({}, surveyStore.formValues)
|
||||||
|
|
||||||
localStorage.setItem(surveyPath.value + '_questionData', JSON.stringify(formData))
|
localstorage.setItem(surveyPath.value + FORMDATA_SUFFIX, formData)
|
||||||
localStorage.setItem('isSubmit', JSON.stringify(true))
|
localstorage.setItem(SUBMIT_FLAG, true)
|
||||||
|
|
||||||
if (encryptInfo?.encryptType) {
|
if (encryptInfo?.encryptType) {
|
||||||
result.encryptType = encryptInfo.encryptType
|
result.encryptType = encryptInfo.encryptType
|
||||||
|
@ -3,9 +3,9 @@ import { defineStore } from 'pinia'
|
|||||||
import { set } from 'lodash-es'
|
import { set } from 'lodash-es'
|
||||||
import { useSurveyStore } from '@/render/stores/survey'
|
import { useSurveyStore } from '@/render/stores/survey'
|
||||||
import { queryVote } from '@/render/api/survey'
|
import { queryVote } from '@/render/api/survey'
|
||||||
import { QUESTION_TYPE, NORMAL_CHOICES } from '@/common/typeEnum'
|
import { QUESTION_TYPE } from '@/common/typeEnum'
|
||||||
|
import { VOTE_INFO_KEY } from '@/render/utils/constant'
|
||||||
const VOTE_INFO_KEY = 'voteinfo'
|
import localstorage from '@/common/localstorage'
|
||||||
|
|
||||||
// 投票进度逻辑聚合
|
// 投票进度逻辑聚合
|
||||||
const usevVoteMap = (questionData) => {
|
const usevVoteMap = (questionData) => {
|
||||||
@ -28,19 +28,16 @@ const usevVoteMap = (questionData) => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
localStorage.removeItem(VOTE_INFO_KEY)
|
localstorage.removeItem(VOTE_INFO_KEY)
|
||||||
const voteRes = await queryVote({
|
const voteRes = await queryVote({
|
||||||
surveyPath,
|
surveyPath,
|
||||||
fieldList: fieldList.join(',')
|
fieldList: fieldList.join(',')
|
||||||
})
|
})
|
||||||
|
|
||||||
if (voteRes.code === 200) {
|
if (voteRes.code === 200) {
|
||||||
localStorage.setItem(
|
localstorage.setItem(VOTE_INFO_KEY, {
|
||||||
VOTE_INFO_KEY,
|
...voteRes.data
|
||||||
JSON.stringify({
|
})
|
||||||
...voteRes.data
|
|
||||||
})
|
|
||||||
)
|
|
||||||
setVoteMap(voteRes.data)
|
setVoteMap(voteRes.data)
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -60,9 +57,8 @@ const usevVoteMap = (questionData) => {
|
|||||||
}
|
}
|
||||||
const updateVoteData = (data) => {
|
const updateVoteData = (data) => {
|
||||||
const { key: questionKey, value: questionVal } = data
|
const { key: questionKey, value: questionVal } = data
|
||||||
// 更新前获取接口缓存在localStorage中的数据
|
// 更新前获取接口缓存在localstorage中的数据
|
||||||
const localData = localStorage.getItem(VOTE_INFO_KEY)
|
const voteinfo = localstorage.getItem(VOTE_INFO_KEY)
|
||||||
const voteinfo = JSON.parse(localData)
|
|
||||||
const currentQuestion = questionData.value[questionKey]
|
const currentQuestion = questionData.value[questionKey]
|
||||||
const options = currentQuestion.options
|
const options = currentQuestion.options
|
||||||
const voteTotal = voteinfo?.[questionKey]?.total || 0
|
const voteTotal = voteinfo?.[questionKey]?.total || 0
|
||||||
|
@ -2,23 +2,24 @@ import { ref } from 'vue'
|
|||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { cloneDeep, pick } from 'lodash-es'
|
import { cloneDeep, pick } from 'lodash-es'
|
||||||
|
|
||||||
import { isMobile as isInMobile } from '@/render/utils/index'
|
|
||||||
import { getEncryptInfo as getEncryptInfoApi } from '@/render/api/survey'
|
|
||||||
import { useQuestionStore } from '@/render/stores/question'
|
|
||||||
import { useErrorInfo } from '@/render/stores/errorInfo'
|
|
||||||
|
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
// 引入中文
|
// 引入中文
|
||||||
import 'moment/locale/zh-cn'
|
import 'moment/locale/zh-cn'
|
||||||
// 设置中文
|
// 设置中文
|
||||||
|
|
||||||
|
import { isMobile as isInMobile } from '@/render/utils/index'
|
||||||
|
import { getEncryptInfo as getEncryptInfoApi } from '@/render/api/survey'
|
||||||
|
import { useQuestionStore } from '@/render/stores/question'
|
||||||
|
import { useErrorInfo } from '@/render/stores/errorInfo'
|
||||||
|
import { FORMDATA_SUFFIX, SUBMIT_FLAG } from '@/render/utils/constant'
|
||||||
|
|
||||||
import adapter from '../adapter'
|
import adapter from '../adapter'
|
||||||
import { RuleMatch } from '@/common/logicEngine/RulesMatch'
|
import { RuleMatch } from '@/common/logicEngine/RulesMatch'
|
||||||
import useCommandComponent from '../hooks/useCommandComponent'
|
import useCommandComponent from '../hooks/useCommandComponent'
|
||||||
import BackAnswerDialog from '../components/BackAnswerDialog.vue'
|
import ConfirmDialog from '../components/ConfirmDialog.vue'
|
||||||
|
import localstorage from '@/common/localstorage'
|
||||||
|
|
||||||
const confirm = useCommandComponent(BackAnswerDialog)
|
const confirm = useCommandComponent(ConfirmDialog)
|
||||||
|
|
||||||
moment.locale('zh-cn')
|
moment.locale('zh-cn')
|
||||||
/**
|
/**
|
||||||
@ -134,7 +135,7 @@ export const useSurveyStore = defineStore('survey', () => {
|
|||||||
'pageConf'
|
'pageConf'
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
// todo: 建议通过questionStore提供setqueationdata方法修改属性,否则不好跟踪变化
|
|
||||||
questionStore.questionData = questionData
|
questionStore.questionData = questionData
|
||||||
questionStore.questionSeq = questionSeq
|
questionStore.questionSeq = questionSeq
|
||||||
|
|
||||||
@ -168,52 +169,29 @@ export const useSurveyStore = defineStore('survey', () => {
|
|||||||
// 加载空白问卷
|
// 加载空白问卷
|
||||||
clearFormData(option)
|
clearFormData(option)
|
||||||
|
|
||||||
const { breakAnswer, backAnswer } = option.baseConf
|
const { fillAnswer, fillSubmitAnswer } = option.baseConf
|
||||||
const localData = JSON.parse(localStorage.getItem(surveyPath.value + '_questionData'))
|
const localData = localstorage.getItem(surveyPath.value + FORMDATA_SUFFIX)
|
||||||
|
|
||||||
const isSubmit = JSON.parse(localStorage.getItem('isSubmit'))
|
const isSubmit = localstorage.getItem(SUBMIT_FLAG)
|
||||||
|
// 开启了断点续答 or 回填上一次提交内容
|
||||||
if (localData) {
|
if ((fillAnswer || (fillSubmitAnswer && isSubmit)) && localData) {
|
||||||
// 断点续答
|
const title = fillAnswer ? '是否继续上次填写的内容?' : '是否继续上次提交的内容?'
|
||||||
if (breakAnswer) {
|
confirm({
|
||||||
confirm({
|
title: title,
|
||||||
title: '是否继续上次填写的内容?',
|
onConfirm: async () => {
|
||||||
onConfirm: async () => {
|
try {
|
||||||
try {
|
// 回填答题内容
|
||||||
// 回填答题内容
|
fillFormData(localData)
|
||||||
fillFormData(localData)
|
} catch (error) {
|
||||||
} catch (error) {
|
console.error(error)
|
||||||
console.log(error)
|
} finally {
|
||||||
} finally {
|
|
||||||
confirm.close()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onCancel: async () => {
|
|
||||||
confirm.close()
|
confirm.close()
|
||||||
}
|
}
|
||||||
})
|
},
|
||||||
} else if (backAnswer) {
|
onClose: async () => {
|
||||||
if (isSubmit) {
|
confirm.close()
|
||||||
confirm({
|
|
||||||
title: '是否继续上次提交的内容?',
|
|
||||||
onConfirm: async () => {
|
|
||||||
try {
|
|
||||||
// 回填答题内容
|
|
||||||
fillFormData(localData)
|
|
||||||
} catch (error) {
|
|
||||||
console.log(error)
|
|
||||||
} finally {
|
|
||||||
confirm.close()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onCancel: async () => {
|
|
||||||
confirm.close()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
} else {
|
|
||||||
clearFormData(option)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
5
web/src/render/utils/constant.ts
Normal file
5
web/src/render/utils/constant.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export const VOTE_INFO_KEY = 'voteinfo'
|
||||||
|
export const QUOTA_INFO_KEY = 'limitinfo'
|
||||||
|
|
||||||
|
export const SUBMIT_FLAG = 'isSubmit'
|
||||||
|
export const FORMDATA_SUFFIX = '_questionData'
|
@ -16,7 +16,7 @@ export default class EventBus {
|
|||||||
|
|
||||||
off(eventName, fn) {
|
off(eventName, fn) {
|
||||||
if (this.events[eventName]) {
|
if (this.events[eventName]) {
|
||||||
for (var i = 0; i < this.events[eventName].length; i++) {
|
for (let i = 0; i < this.events[eventName].length; i++) {
|
||||||
if (this.events[eventName][i] === fn) {
|
if (this.events[eventName][i] === fn) {
|
||||||
this.events[eventName].splice(i, 1)
|
this.events[eventName].splice(i, 1)
|
||||||
break
|
break
|
||||||
|
Loading…
Reference in New Issue
Block a user