Feature/vue3 (#98)
* wip: vue3 * fix: dev时C端路由被B端router污染 * wip: debugger material * wip: render widgets * wip:回滚editOption * c端抽离编辑态组件 * wip * 事件调通 * wip * feat: 可以正常提交 * fix: typo * fix: 答题进度条 * fix: form 与 input 事件冲突 * 优化field管理 * 优化代码 * update * 标题组件 * fix: 组件操作图标样式 --------- Co-authored-by: taoshaung <taoshaung@didiglobal.com>
@ -1,20 +1,15 @@
|
|||||||
|
/* eslint-env node */
|
||||||
|
require('@rushstack/eslint-patch/modern-module-resolution')
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
root: false,
|
root: true,
|
||||||
env: {
|
'extends': [
|
||||||
node: true,
|
'plugin:vue/vue3-essential',
|
||||||
},
|
|
||||||
extends: [
|
|
||||||
'plugin:vue/essential',
|
|
||||||
'eslint:recommended',
|
'eslint:recommended',
|
||||||
'plugin:prettier/recommended',
|
'@vue/eslint-config-typescript',
|
||||||
|
'@vue/eslint-config-prettier/skip-formatting'
|
||||||
],
|
],
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
parser: '@babel/eslint-parser',
|
ecmaVersion: 'latest'
|
||||||
},
|
}
|
||||||
rules: {
|
}
|
||||||
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
|
|
||||||
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
|
|
||||||
'vue/multi-word-component-names': 'off',
|
|
||||||
semi: ['error', 'always'],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
1
web/.gitignore
vendored
@ -14,6 +14,7 @@ yarn-debug.log*
|
|||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
pnpm-debug.log*
|
pnpm-debug.log*
|
||||||
package-lock.json
|
package-lock.json
|
||||||
|
pnpm-lock.yaml
|
||||||
|
|
||||||
# Editor directories and files
|
# Editor directories and files
|
||||||
.idea
|
.idea
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
singleQuote: true, // 使用单引号
|
|
||||||
semi: true, // 不使用分号
|
|
||||||
// trailingComma: 'all', // 在对象和数组末尾加上逗号
|
|
||||||
};
|
|
8
web/.prettierrc.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json.schemastore.org/prettierrc",
|
||||||
|
"semi": false,
|
||||||
|
"tabWidth": 2,
|
||||||
|
"singleQuote": true,
|
||||||
|
"printWidth": 100,
|
||||||
|
"trailingComma": "none"
|
||||||
|
}
|
8
web/env.d.ts
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
/// <reference types="vite/client" />
|
||||||
|
declare module "vuex" {
|
||||||
|
export * from "vuex/types/index.d.ts";
|
||||||
|
export * from "vuex/types/helpers.d.ts";
|
||||||
|
export * from "vuex/types/logger.d.ts";
|
||||||
|
export * from "vuex/types/vue.d.ts";
|
||||||
|
}
|
||||||
|
|
@ -2,55 +2,53 @@
|
|||||||
"name": "web",
|
"name": "web",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"serve": "vue-cli-service serve",
|
"serve": "vite",
|
||||||
"build": "vue-cli-service build",
|
"dev": "vite",
|
||||||
"report": "vue-cli-service build --report",
|
"build": "run-p type-check \"build-only {@}\" --",
|
||||||
"lint": "vue-cli-service lint",
|
"preview": "vite preview",
|
||||||
"lintfix": "eslint --fix ."
|
"build-only": "vite build",
|
||||||
|
"type-check": "vue-tsc --build --force",
|
||||||
|
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/babel-helper-vue-jsx-merge-props": "^1.4.0",
|
"@element-plus/icons-vue": "^2.3.1",
|
||||||
"@vue/babel-preset-jsx": "^1.4.0",
|
|
||||||
"@wangeditor/editor": "^5.1.23",
|
"@wangeditor/editor": "^5.1.23",
|
||||||
|
"@wangeditor/editor-for-vue": "^5.1.12",
|
||||||
"async-validator": "^4.2.5",
|
"async-validator": "^4.2.5",
|
||||||
"axios": "^1.4.0",
|
"axios": "^1.4.0",
|
||||||
"clipboard": "^2.0.11",
|
"clipboard": "^2.0.11",
|
||||||
"core-js": "^3.8.3",
|
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
"element-ui": "^2.15.13",
|
"element-plus": "^2.5.5",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"moment": "^2.29.4",
|
"moment": "^2.29.4",
|
||||||
"node-forge": "^1.3.1",
|
"node-forge": "^1.3.1",
|
||||||
"qrcode": "^1.5.3",
|
"qrcode": "^1.5.3",
|
||||||
"vue": "^2.7.14",
|
"vue": "^3.4.15",
|
||||||
"vue-router": "^3.5.1",
|
"vue-router": "^4.2.5",
|
||||||
"vuedraggable": "^2.24.3",
|
"vuedraggable": "^4.1.0",
|
||||||
"vuex": "^3.6.2",
|
"vuex": "^4.0.2",
|
||||||
"xss": "^1.0.14"
|
"xss": "^1.0.14"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.12.16",
|
"@tsconfig/node20": "^20.1.2",
|
||||||
"@babel/eslint-parser": "^7.12.16",
|
"@types/node": "^20.11.19",
|
||||||
"@vue/cli-plugin-babel": "~5.0.0",
|
"@vitejs/plugin-vue": "^5.0.3",
|
||||||
"@vue/cli-plugin-eslint": "~5.0.0",
|
"@vitejs/plugin-vue-jsx": "^3.1.0",
|
||||||
"@vue/cli-plugin-router": "~5.0.0",
|
"@vue/eslint-config-prettier": "^8.0.0",
|
||||||
"@vue/cli-plugin-vuex": "~5.0.0",
|
"@vue/eslint-config-typescript": "^12.0.0",
|
||||||
"@vue/cli-service": "~5.0.0",
|
"@vue/tsconfig": "^0.5.1",
|
||||||
"eslint": "^7.32.0",
|
"eslint": "^8.49.0",
|
||||||
"eslint-config-prettier": "^8.3.0",
|
"eslint-plugin-vue": "^9.17.0",
|
||||||
"eslint-plugin-prettier": "^4.0.0",
|
"npm-run-all2": "^6.1.1",
|
||||||
"eslint-plugin-vue": "^8.7.1",
|
"prettier": "^3.0.3",
|
||||||
"less-loader": "^11.1.3",
|
"sass": "^1.72.0",
|
||||||
"postcss-import": "^15.1.0",
|
"typescript": "~5.3.0",
|
||||||
"postcss-url": "^10.1.3",
|
"unplugin-element-plus": "^0.8.0",
|
||||||
"prettier": "^2.4.1",
|
"vite": "^5.1.4",
|
||||||
"sass": "^1.32.7",
|
"vite-plugin-virtual-mpa": "^1.10.1",
|
||||||
"sass-loader": "^12.0.0",
|
"vue-tsc": "^1.8.27"
|
||||||
"speed-measure-webpack-plugin": "^1.5.0",
|
|
||||||
"style-resources-loader": "^1.5.0",
|
|
||||||
"vue-style-loader": "^4.1.3",
|
|
||||||
"vue-template-compiler": "^2.7.14"
|
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=14.21.0",
|
"node": ">=14.21.0",
|
||||||
|
Before Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 148 KiB |
Before Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 9.0 KiB |
Before Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 86 KiB |
Before Width: | Height: | Size: 84 KiB |
Before Width: | Height: | Size: 151 KiB |
Before Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 39 KiB |
Before Width: | Height: | Size: 173 KiB |
Before Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 98 KiB |
Before Width: | Height: | Size: 78 KiB |
Before Width: | Height: | Size: 45 KiB |
Before Width: | Height: | Size: 78 KiB |
Before Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 137 KiB |
Before Width: | Height: | Size: 139 KiB |
Before Width: | Height: | Size: 59 KiB |
Before Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 57 KiB |
Before Width: | Height: | Size: 112 KiB |
Before Width: | Height: | Size: 153 KiB |
Before Width: | Height: | Size: 53 KiB |
Before Width: | Height: | Size: 76 KiB |
Before Width: | Height: | Size: 158 KiB |
Before Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 101 KiB |
Before Width: | Height: | Size: 78 KiB |
Before Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 106 KiB |
Before Width: | Height: | Size: 45 KiB |
Before Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 141 KiB |
Before Width: | Height: | Size: 79 KiB |
Before Width: | Height: | Size: 45 KiB |
Before Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 124 KiB |
Before Width: | Height: | Size: 111 KiB |
Before Width: | Height: | Size: 62 KiB |
Before Width: | Height: | Size: 115 KiB |
@ -1,10 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="editor-v2">
|
<div class="editor-v2">
|
||||||
<RichEditor :value="realData" @input="handleChange" @blur="handleBlur" />
|
<RichEditor :modelValue="realData" @input="handleChange" @blur="handleBlur" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import RichEditor from './RichEditor';
|
import RichEditor from './RichEditor.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
@ -1,118 +1,111 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="editor-wrapper border">
|
<div class="editor-wrapper border">
|
||||||
<div class="toolbar" ref="toolbar" v-show="showToolbar"></div>
|
<Toolbar
|
||||||
<div class="editor" ref="editor"></div>
|
:class="['toolbar',props.staticToolBar ? 'static-toolbar' : 'dynamic-toolbar']"
|
||||||
|
ref="toolbar"
|
||||||
|
v-show="showToolbar"
|
||||||
|
:editor="editorRef"
|
||||||
|
:defaultConfig="toolbarConfig"
|
||||||
|
:mode="mode"
|
||||||
|
/>
|
||||||
|
<Editor
|
||||||
|
class="editor"
|
||||||
|
ref="editor"
|
||||||
|
:modelValue="curValue"
|
||||||
|
:defaultConfig="editorConfig"
|
||||||
|
@onCreated="onCreated"
|
||||||
|
@onChange="onChange"
|
||||||
|
@onBlur="onBlur"
|
||||||
|
@onFocus="onFocus"
|
||||||
|
:mode="mode"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup>
|
||||||
import { createEditor, createToolbar } from '@wangeditor/editor';
|
import '@wangeditor/editor/dist/css/style.css'
|
||||||
|
import '@/management/styles/reset-wangeditor.scss'
|
||||||
|
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
|
||||||
|
import { ref, shallowRef, onBeforeMount, watch } from 'vue';
|
||||||
|
|
||||||
export default {
|
const emit = defineEmits(['input', 'onFocus', 'change', 'blur'])
|
||||||
name: 'richEditor',
|
const model = defineModel()
|
||||||
data() {
|
const props = defineProps(['staticToolBar'])
|
||||||
return {
|
|
||||||
curValue: '',
|
const curValue = ref('')
|
||||||
editor: null,
|
const editorRef = shallowRef()
|
||||||
showToolbar: false,
|
const showToolbar = ref(props.staticToolBar || false)
|
||||||
};
|
|
||||||
},
|
const mode = 'simple'
|
||||||
props: ['value'], // value 用于自定义 v-model
|
|
||||||
mounted() {
|
const toolbarConfig = {
|
||||||
this.create();
|
toolbarKeys: [
|
||||||
},
|
'color', // 字体色
|
||||||
watch: {
|
'bgColor', // 背景色
|
||||||
value: {
|
'bold',
|
||||||
immediate: true,
|
'insertLink', // 链接
|
||||||
handler(newVal) {
|
],
|
||||||
const isEqual = newVal === this.curValue;
|
}
|
||||||
if (isEqual) return; // 和当前内容一样,则忽略
|
|
||||||
|
const editorConfig = {}
|
||||||
|
|
||||||
|
const setHtml = (newHtml) => {
|
||||||
|
const editor = editorRef.value;
|
||||||
|
if (editor == null) return;
|
||||||
|
editor.setHtml(newHtml);
|
||||||
|
}
|
||||||
|
|
||||||
|
const onCreated = (editor) => {
|
||||||
|
editorRef.value = editor
|
||||||
|
if (model.value) {
|
||||||
|
setHtml(model.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const onChange = (editor) => {
|
||||||
|
const editorHtml = editor.getHtml();
|
||||||
|
curValue.value = editorHtml; // 记录当前 html 内容
|
||||||
|
emit('input', editorHtml); // 用于自定义 v-model
|
||||||
|
}
|
||||||
|
const onFocus = (editor) => {
|
||||||
|
emit('onFocus', editor);
|
||||||
|
setToolbarStatus(true);
|
||||||
|
}
|
||||||
|
const onBlur = (editor) => {
|
||||||
|
const editorHtml = editor.getHtml();
|
||||||
|
curValue.value = editorHtml; // 记录当前 html 内容
|
||||||
|
emit('change', editorHtml);
|
||||||
|
emit('blur', editor);
|
||||||
|
setToolbarStatus(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const setToolbarStatus = (status) => {
|
||||||
|
if(props.staticToolBar) return
|
||||||
|
showToolbar.value = status
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => model.value,
|
||||||
|
(newVal) => {
|
||||||
|
const isEqual = newVal === curValue.value;
|
||||||
|
if (isEqual) return; // 和当前内容一样,则忽略
|
||||||
|
|
||||||
// 重置 HTML
|
|
||||||
this.setHtml(newVal);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
// 重置 HTML
|
// 重置 HTML
|
||||||
setHtml(newHtml) {
|
setHtml(newVal);
|
||||||
const editor = this.editor;
|
|
||||||
if (editor === null) return;
|
|
||||||
editor.setHtml(newHtml);
|
|
||||||
},
|
|
||||||
// 创建 editor
|
|
||||||
create() {
|
|
||||||
if (this.$refs.editor === null) return;
|
|
||||||
|
|
||||||
createEditor({
|
|
||||||
selector: this.$refs.editor,
|
|
||||||
html: this.defaultHtml || this.value || '',
|
|
||||||
config: {
|
|
||||||
onCreated: (editor) => {
|
|
||||||
this.editor = Object.seal(editor);
|
|
||||||
|
|
||||||
if (this.value) {
|
|
||||||
this.setHtml(this.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$refs.toolbar &&
|
|
||||||
createToolbar({
|
|
||||||
editor,
|
|
||||||
selector: this.$refs.toolbar,
|
|
||||||
config: {
|
|
||||||
toolbarKeys: [
|
|
||||||
'color', // 字体色
|
|
||||||
'bgColor', // 背景色
|
|
||||||
'bold',
|
|
||||||
// 'insertImage', // 插入图片
|
|
||||||
// 'video',
|
|
||||||
// 'fontSize', // 字号
|
|
||||||
// 'justify', // 对齐方式
|
|
||||||
'insertLink', // 链接
|
|
||||||
// 'clean',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
mode: 'simple',
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onChange: (editor) => {
|
|
||||||
const editorHtml = editor.getHtml();
|
|
||||||
this.curValue = editorHtml; // 记录当前 html 内容
|
|
||||||
this.$emit('input', editorHtml); // 用于自定义 v-model
|
|
||||||
},
|
|
||||||
onDestroyed: (editor) => {
|
|
||||||
this.$emit('onDestroyed', editor);
|
|
||||||
editor.destroy();
|
|
||||||
},
|
|
||||||
onFocus: (editor) => {
|
|
||||||
this.$emit('onFocus', editor);
|
|
||||||
this.showToolbar = true;
|
|
||||||
},
|
|
||||||
onBlur: (editor) => {
|
|
||||||
const editorHtml = editor.getHtml();
|
|
||||||
this.curValue = editorHtml; // 记录当前 html 内容
|
|
||||||
this.$emit('change', editorHtml);
|
|
||||||
this.$emit('blur', editor);
|
|
||||||
this.showToolbar = false;
|
|
||||||
},
|
|
||||||
// customPaste: (editor, event) => {
|
|
||||||
// let res;
|
|
||||||
// this.$emit('customPaste', editor, event, (val) => {
|
|
||||||
// res = val;
|
|
||||||
// });
|
|
||||||
// return res;
|
|
||||||
// },
|
|
||||||
},
|
|
||||||
content: [],
|
|
||||||
mode: 'simple',
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
{
|
||||||
|
// immediate: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
onBeforeMount(() => {
|
||||||
|
const editor = editorRef.value
|
||||||
|
if (editor == null) return
|
||||||
|
editor.destroy()
|
||||||
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import url('@wangeditor/editor/dist/css/style.css');
|
|
||||||
@import url('@/management/styles/reset-wangeditor.scss');
|
|
||||||
|
|
||||||
.editor-wrapper {
|
.editor-wrapper {
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -120,7 +113,10 @@ export default {
|
|||||||
// min-height: 45px;
|
// min-height: 45px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toolbar {
|
.static-toolbar {
|
||||||
|
border-bottom: 1px solid #dedede;
|
||||||
|
}
|
||||||
|
.dynamic-toolbar {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
top: -44px;
|
top: -44px;
|
||||||
|
@ -3,11 +3,13 @@
|
|||||||
<router-view></router-view>
|
<router-view></router-view>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: 'App',
|
name: 'App',
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import url('./styles/icon.scss');
|
@import url('./styles/icon.scss');
|
||||||
@import url('../materials/questions/common/css/icon.scss');
|
@import url('../materials/questions/common/css/icon.scss');
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import axios from './base';
|
import axios from './base'
|
||||||
|
|
||||||
export const getRecycleList = (data) => {
|
export const getRecycleList = (data) => {
|
||||||
return axios.get('/survey/dataStatistic/dataTable', {
|
return axios.get('/survey/dataStatistic/dataTable', {
|
||||||
@ -6,5 +6,5 @@ export const getRecycleList = (data) => {
|
|||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
...data,
|
...data,
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
};
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import axios from './base';
|
import axios from './base'
|
||||||
|
|
||||||
export const register = (data) => {
|
export const register = (data) => {
|
||||||
return axios.post('/auth/register', data);
|
return axios.post('/auth/register', data)
|
||||||
};
|
}
|
||||||
|
|
||||||
export const login = (data) => {
|
export const login = (data) => {
|
||||||
return axios.post('/auth/login', data);
|
return axios.post('/auth/login', data)
|
||||||
};
|
}
|
||||||
|
@ -1,49 +1,49 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios'
|
||||||
import store from '@/management/store/index';
|
import store from '@/management/store/index'
|
||||||
import router from '@/management/router/index';
|
import router from '@/management/router/index'
|
||||||
import { get as _get } from 'lodash-es';
|
import { get as _get } from 'lodash-es'
|
||||||
|
|
||||||
const instance = axios.create({
|
const instance = axios.create({
|
||||||
baseURL: '/api',
|
baseURL: '/api',
|
||||||
timeout: 10000,
|
timeout: 10000,
|
||||||
});
|
})
|
||||||
|
|
||||||
instance.interceptors.response.use(
|
instance.interceptors.response.use(
|
||||||
(response) => {
|
(response) => {
|
||||||
if (response.status !== 200) {
|
if (response.status !== 200) {
|
||||||
throw new Error('http请求出错');
|
throw new Error('http请求出错')
|
||||||
}
|
}
|
||||||
const res = response.data;
|
const res = response.data
|
||||||
if (res.code === 403) {
|
if (res.code === 403) {
|
||||||
router.replace({
|
router.replace({
|
||||||
name: 'login',
|
name: 'login',
|
||||||
});
|
})
|
||||||
return res;
|
return res
|
||||||
} else {
|
} else {
|
||||||
return res;
|
return res
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
(err) => {
|
(err) => {
|
||||||
throw new Error(err);
|
throw new Error(err)
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
|
|
||||||
instance.interceptors.request.use((config) => {
|
instance.interceptors.request.use((config) => {
|
||||||
const hasLogined = _get(store, 'state.user.hasLogined');
|
const hasLogined = _get(store, 'state.user.hasLogined')
|
||||||
const token = _get(store, 'state.user.userInfo.token');
|
const token = _get(store, 'state.user.userInfo.token')
|
||||||
if (hasLogined && token) {
|
if (hasLogined && token) {
|
||||||
if (!config.headers) {
|
if (!config.headers) {
|
||||||
config.headers = {};
|
config.headers = {}
|
||||||
}
|
}
|
||||||
config.headers.Authorization = `Bearer ${token}`;
|
config.headers.Authorization = `Bearer ${token}`
|
||||||
}
|
}
|
||||||
return config;
|
return config
|
||||||
});
|
})
|
||||||
|
|
||||||
export default instance;
|
export default instance
|
||||||
|
|
||||||
export const CODE_MAP = {
|
export const CODE_MAP = {
|
||||||
SUCCESS: 200,
|
SUCCESS: 200,
|
||||||
ERROR: 500,
|
ERROR: 500,
|
||||||
NOTAUTH: 403,
|
NOTAUTH: 403,
|
||||||
};
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import axios from './base';
|
import axios from './base'
|
||||||
|
|
||||||
export const refreshCaptcha = ({ captchaId }) => {
|
export const refreshCaptcha = ({ captchaId }) => {
|
||||||
return axios.post('/auth/captcha', { captchaId });
|
return axios.post('/auth/captcha', { captchaId })
|
||||||
};
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import axios from './base';
|
import axios from './base'
|
||||||
|
|
||||||
export const getBannerData = () => {
|
export const getBannerData = () => {
|
||||||
return axios.get('/survey/getBannerData');
|
return axios.get('/survey/getBannerData')
|
||||||
};
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import axios from './base';
|
import axios from './base'
|
||||||
|
|
||||||
export const getSurveyList = ({ curPage, filter, order }) => {
|
export const getSurveyList = ({ curPage, filter, order }) => {
|
||||||
return axios.get('/survey/getList', {
|
return axios.get('/survey/getList', {
|
||||||
@ -8,30 +8,30 @@ export const getSurveyList = ({ curPage, filter, order }) => {
|
|||||||
filter,
|
filter,
|
||||||
order,
|
order,
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
};
|
}
|
||||||
|
|
||||||
export const getSurveyById = (id) => {
|
export const getSurveyById = (id) => {
|
||||||
return axios.get('/survey/getSurvey', {
|
return axios.get('/survey/getSurvey', {
|
||||||
params: {
|
params: {
|
||||||
surveyId: id,
|
surveyId: id,
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
};
|
}
|
||||||
|
|
||||||
export const saveSurvey = ({ surveyId, configData }) => {
|
export const saveSurvey = ({ surveyId, configData }) => {
|
||||||
return axios.post('/survey/updateConf', { surveyId, configData });
|
return axios.post('/survey/updateConf', { surveyId, configData })
|
||||||
};
|
}
|
||||||
|
|
||||||
export const publishSurvey = ({ surveyId }) => {
|
export const publishSurvey = ({ surveyId }) => {
|
||||||
return axios.post('/survey/publishSurvey', {
|
return axios.post('/survey/publishSurvey', {
|
||||||
surveyId,
|
surveyId,
|
||||||
});
|
})
|
||||||
};
|
}
|
||||||
|
|
||||||
export const createSurvey = (data) => {
|
export const createSurvey = (data) => {
|
||||||
return axios.post('/survey/createSurvey', data);
|
return axios.post('/survey/createSurvey', data)
|
||||||
};
|
}
|
||||||
|
|
||||||
export const getSurveyHistory = ({ surveyId, historyType }) => {
|
export const getSurveyHistory = ({ surveyId, historyType }) => {
|
||||||
return axios.get('/surveyHisotry/getList', {
|
return axios.get('/surveyHisotry/getList', {
|
||||||
@ -39,15 +39,15 @@ export const getSurveyHistory = ({ surveyId, historyType }) => {
|
|||||||
surveyId,
|
surveyId,
|
||||||
historyType,
|
historyType,
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
};
|
}
|
||||||
|
|
||||||
export const deleteSurvey = (surveyId) => {
|
export const deleteSurvey = (surveyId) => {
|
||||||
return axios.post('/survey/deleteSurvey', {
|
return axios.post('/survey/deleteSurvey', {
|
||||||
surveyId,
|
surveyId,
|
||||||
});
|
})
|
||||||
};
|
}
|
||||||
|
|
||||||
export const updateSurvey = (data) => {
|
export const updateSurvey = (data) => {
|
||||||
return axios.post('/survey/updateMeta', data);
|
return axios.post('/survey/updateMeta', data)
|
||||||
};
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<div class="default-empty-root">
|
<div class="default-empty-root">
|
||||||
<img class="img" :src="data.img" />
|
<img class="img" :src="data.img" />
|
||||||
<div class="title">{{ data.title }}</div>
|
<div class="title">{{ data.title }}</div>
|
||||||
<div class="desc" v-html="data.desc" />
|
<div class="desc" v-html="data.desc"></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -15,7 +15,7 @@ export default {
|
|||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" rel="stylesheet/scss" scoped>
|
<style lang="scss" rel="stylesheet/scss" scoped>
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import logo from './logo.vue';
|
import logo from './logo.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'leftMenu',
|
name: 'leftMenu',
|
||||||
@ -49,9 +49,9 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
<img src="/imgs/s-logo.webp" />
|
<img src="/imgs/s-logo.webp" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: 'logoIcon',
|
name: 'logoIcon',
|
||||||
@ -10,11 +11,12 @@ export default {
|
|||||||
toHomePage() {
|
toHomePage() {
|
||||||
this.$router.push({
|
this.$router.push({
|
||||||
name: 'survey',
|
name: 'survey',
|
||||||
});
|
})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.navbar-main-logo {
|
.navbar-main-logo {
|
||||||
width: 80px;
|
width: 80px;
|
||||||
|
44
web/src/management/config/defaultSurveyConfig.js
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
export default {
|
||||||
|
metaData: null,
|
||||||
|
bannerConf: {
|
||||||
|
titleConfig: {
|
||||||
|
mainTitle: '<h3 style="text-align: center">欢迎填写问卷</h3>',
|
||||||
|
subTitle: `<p>为了给您提供更好的服务,希望您能抽出几分钟时间,将您的感受和建议告诉我们,<span style="color: rgb(204, 0, 0)">期待您的参与!</span></p>`,
|
||||||
|
applyTitle: '',
|
||||||
|
},
|
||||||
|
bannerConfig: {
|
||||||
|
bgImage: '',
|
||||||
|
bgImageAllowJump: false,
|
||||||
|
bgImageJumpLink: '',
|
||||||
|
videoLink: '',
|
||||||
|
postImg: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
bottomConf: {
|
||||||
|
logoImage: '',
|
||||||
|
logoImageWidth: '28%',
|
||||||
|
},
|
||||||
|
skinConf: {
|
||||||
|
skinColor: '#4a4c5b',
|
||||||
|
inputBgColor: '#ffffff',
|
||||||
|
},
|
||||||
|
baseConf: {
|
||||||
|
begTime: '',
|
||||||
|
endTime: '',
|
||||||
|
language: 'chinese',
|
||||||
|
showVoteProcess: 'allow',
|
||||||
|
tLimit: 0,
|
||||||
|
answerBegTime: '',
|
||||||
|
answerEndTime: '',
|
||||||
|
answerLimitTime: 0,
|
||||||
|
},
|
||||||
|
submitConf: {
|
||||||
|
submitTitle: '',
|
||||||
|
msgContent: {},
|
||||||
|
confirmAgain: {
|
||||||
|
is_again: true,
|
||||||
|
},
|
||||||
|
link: '',
|
||||||
|
},
|
||||||
|
questionDataList: [],
|
||||||
|
};
|
@ -74,4 +74,4 @@ export const defaultQuestionConfig = {
|
|||||||
value: 500,
|
value: 500,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
|
@ -55,7 +55,7 @@ const menuItems = {
|
|||||||
icon: 'tixing-toupiao',
|
icon: 'tixing-toupiao',
|
||||||
title: '投票',
|
title: '投票',
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
|
|
||||||
const menuGroup = [
|
const menuGroup = [
|
||||||
{
|
{
|
||||||
@ -73,15 +73,13 @@ const menuGroup = [
|
|||||||
'vote',
|
'vote',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
]
|
||||||
|
|
||||||
const menu = menuGroup.map((group) => {
|
const menu = menuGroup.map((group) => {
|
||||||
group.questionList = group.questionList.map(
|
group.questionList = group.questionList.map((question) => menuItems[question])
|
||||||
(question) => menuItems[question]
|
return group
|
||||||
);
|
})
|
||||||
return group;
|
|
||||||
});
|
|
||||||
|
|
||||||
export const questionTypeList = Object.values(menuItems);
|
export const questionTypeList = Object.values(menuItems)
|
||||||
|
|
||||||
export default menu;
|
export default menu
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
export default [
|
export default [
|
||||||
{
|
{
|
||||||
label: '顶部图片地址',
|
label: '顶部图片地址',
|
||||||
@ -37,5 +38,22 @@ export default [
|
|||||||
relyFunc: (data) => {
|
relyFunc: (data) => {
|
||||||
return !!data?.bgImageAllowJump;
|
return !!data?.bgImageAllowJump;
|
||||||
},
|
},
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
label: '图片支持点击',
|
||||||
|
type: 'CustomedSwitch',
|
||||||
|
direction: 'space_between',
|
||||||
|
key: 'bannerConfig.bgImageAllowJump',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '跳转链接',
|
||||||
|
type: 'Input',
|
||||||
|
direction: 'horizon',
|
||||||
|
key: 'bannerConfig.bgImageJumpLink',
|
||||||
|
relyFunc: (data) => {
|
||||||
|
return !!data?.bannerConfig?.bgImageAllowJump
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
];
|
]
|
||||||
|
@ -15,4 +15,4 @@ export default [
|
|||||||
direction: 'horizon',
|
direction: 'horizon',
|
||||||
labelStyle: { width: '120px' }
|
labelStyle: { width: '120px' }
|
||||||
},
|
},
|
||||||
];
|
]
|
||||||
|
@ -68,4 +68,4 @@ export default [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
]
|
||||||
|
16
web/src/management/directive/plainText.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { cleanRichText } from '@/common/xss'
|
||||||
|
import type { DirectiveBinding, Directive, Plugin } from 'vue'
|
||||||
|
|
||||||
|
function _plainText(el: HTMLElement, binding: DirectiveBinding) {
|
||||||
|
const text = cleanRichText(binding.value)
|
||||||
|
el.innerText = `${text}`
|
||||||
|
}
|
||||||
|
const plainText: Directive & Plugin = {
|
||||||
|
mounted: _plainText,
|
||||||
|
updated: _plainText,
|
||||||
|
install: function (app) {
|
||||||
|
app.directive('plain-text', this)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default plainText
|
17
web/src/management/directive/safeHtml.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { filterXSS } from '@/common/xss'
|
||||||
|
import type { Directive, Plugin, DirectiveBinding } from 'vue'
|
||||||
|
|
||||||
|
function _safeHtml(el: HTMLElement, binding: DirectiveBinding) {
|
||||||
|
const res = filterXSS(binding.value)
|
||||||
|
el.innerHTML = res
|
||||||
|
}
|
||||||
|
|
||||||
|
const safeHtml: Directive & Plugin = {
|
||||||
|
mounted: _safeHtml,
|
||||||
|
updated: _safeHtml,
|
||||||
|
install: function (app) {
|
||||||
|
app.directive('safe-html', this)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default safeHtml
|
@ -4,11 +4,10 @@
|
|||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||||
<link rel="icon" href="<%= BASE_URL %>imgs/favicon.ico">
|
<link rel="icon" href="/imgs/favicon.ico">
|
||||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
<!-- built files will be auto injected -->
|
<!-- <script type="module" src="./main.ts"></script> -->
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -1,36 +0,0 @@
|
|||||||
import Vue from 'vue';
|
|
||||||
import App from './App.vue';
|
|
||||||
import router from './router';
|
|
||||||
import store from './store';
|
|
||||||
import ElementUI from 'element-ui';
|
|
||||||
import './styles/element-variables.scss';
|
|
||||||
import { filterXSS, cleanRichText } from '@/common/xss';
|
|
||||||
|
|
||||||
Vue.config.productionTip = false;
|
|
||||||
Vue.use(ElementUI);
|
|
||||||
|
|
||||||
const safeHtml = function (el, binding) {
|
|
||||||
const res = filterXSS(binding.value);
|
|
||||||
el.innerHTML = res;
|
|
||||||
};
|
|
||||||
|
|
||||||
const plainText = function (el, binding) {
|
|
||||||
const text = cleanRichText(binding.value);
|
|
||||||
el.innerText = text;
|
|
||||||
};
|
|
||||||
|
|
||||||
Vue.directive('safe-html', {
|
|
||||||
inserted: safeHtml,
|
|
||||||
componentUpdated: safeHtml,
|
|
||||||
});
|
|
||||||
|
|
||||||
Vue.directive('plain-text', {
|
|
||||||
inserted: plainText,
|
|
||||||
componentUpdated: plainText,
|
|
||||||
});
|
|
||||||
|
|
||||||
new Vue({
|
|
||||||
router,
|
|
||||||
store,
|
|
||||||
render: (h) => h(App),
|
|
||||||
}).$mount('#app');
|
|
23
web/src/management/main.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { createApp } from 'vue'
|
||||||
|
import store from './store'
|
||||||
|
import './styles/element-variables.scss'
|
||||||
|
import ElementPlus from 'element-plus'
|
||||||
|
// 手动引入,避免ElMessage动态加载导致的el主题覆盖自定义主题
|
||||||
|
import 'element-plus/theme-chalk/el-message.css'
|
||||||
|
import 'element-plus/theme-chalk/el-message-box.css'
|
||||||
|
import plainText from './directive/plainText'
|
||||||
|
import safeHtml from './directive/safeHtml'
|
||||||
|
|
||||||
|
import App from './App.vue'
|
||||||
|
import router from './router'
|
||||||
|
|
||||||
|
const app = createApp(App)
|
||||||
|
|
||||||
|
app.use(store)
|
||||||
|
app.use(router)
|
||||||
|
app.use(ElementPlus, { size: 'default'})
|
||||||
|
|
||||||
|
app.use(plainText)
|
||||||
|
app.use(safeHtml)
|
||||||
|
|
||||||
|
app.mount('#app')
|
@ -18,7 +18,7 @@
|
|||||||
:label="cleanRichText(item.title)"
|
:label="cleanRichText(item.title)"
|
||||||
minWidth="200"
|
minWidth="200"
|
||||||
>
|
>
|
||||||
<template slot="header" slot-scope="scope">
|
<template #header="scope">
|
||||||
<div class="table-row-cell">
|
<div class="table-row-cell">
|
||||||
<span slot="reference" v-popover="scope.column.id">
|
<span slot="reference" v-popover="scope.column.id">
|
||||||
{{ scope.column.label.replace(/ /g, '') }}
|
{{ scope.column.label.replace(/ /g, '') }}
|
||||||
@ -33,7 +33,7 @@
|
|||||||
</el-popover>
|
</el-popover>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template slot-scope="scope">
|
<template #default="scope">
|
||||||
<span
|
<span
|
||||||
slot="reference"
|
slot="reference"
|
||||||
class="table-row-cell"
|
class="table-row-cell"
|
||||||
@ -54,13 +54,14 @@
|
|||||||
</el-table>
|
</el-table>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { cleanRichText } from '@/common/xss';
|
import { cleanRichText } from '@/common/xss'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'DataTable',
|
name: 'DataTable',
|
||||||
data() {
|
data() {
|
||||||
return {};
|
return {}
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
mainTableLoading: Boolean,
|
mainTableLoading: Boolean,
|
||||||
@ -75,8 +76,9 @@ export default {
|
|||||||
return content === 0 ? 0 : (content || '未知')
|
return content === 0 ? 0 : (content || '未知')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" rel="stylesheet/scss" scoped>
|
<style lang="scss" rel="stylesheet/scss" scoped>
|
||||||
.data-table-wrapper {
|
.data-table-wrapper {
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -89,7 +91,7 @@ export default {
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
::v-deep .el-table__header {
|
:deep(.el-table__header) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
.thead-cell .el-table__cell {
|
.thead-cell .el-table__cell {
|
||||||
.cell {
|
.cell {
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<h2 class="data-list">数据列表</h2>
|
<h2 class="data-list">数据列表</h2>
|
||||||
<div class="menus">
|
<div class="menus">
|
||||||
<el-switch
|
<el-switch
|
||||||
:value="isShowOriginData"
|
:model-value="isShowOriginData"
|
||||||
active-text="是否展示原数据"
|
active-text="是否展示原数据"
|
||||||
@input="onIsShowOriginChange"
|
@input="onIsShowOriginChange"
|
||||||
>
|
>
|
||||||
@ -36,10 +36,10 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import DataTable from './components/table.vue';
|
import DataTable from './components/table.vue'
|
||||||
import empty from '@/management/components/empty';
|
import empty from '@/management/components/empty.vue'
|
||||||
import leftMenu from '@/management/components/leftMenu.vue';
|
import leftMenu from '@/management/components/leftMenu.vue'
|
||||||
import { getRecycleList } from '@/management/api/analysis';
|
import { getRecycleList } from '@/management/api/analysis'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'analysisPage',
|
name: 'analysisPage',
|
||||||
@ -59,71 +59,71 @@ export default {
|
|||||||
currentPage: 1,
|
currentPage: 1,
|
||||||
isShowOriginData: false,
|
isShowOriginData: false,
|
||||||
tmpIsShowOriginData: false,
|
tmpIsShowOriginData: false,
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
computed: {},
|
computed: {},
|
||||||
created() {
|
created() {
|
||||||
this.init();
|
this.init()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async init() {
|
async init() {
|
||||||
if (!this.$route.params.id) {
|
if (!this.$route.params.id) {
|
||||||
this.$message.error('没有传入问卷参数~');
|
this.$message.error('没有传入问卷参数~')
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
this.mainTableLoading = true;
|
this.mainTableLoading = true
|
||||||
try {
|
try {
|
||||||
const res = await getRecycleList({
|
const res = await getRecycleList({
|
||||||
page: this.currentPage,
|
page: this.currentPage,
|
||||||
surveyId: this.$route.params.id,
|
surveyId: this.$route.params.id,
|
||||||
isDesensitive: !this.tmpIsShowOriginData, // 发起请求的时候,isShowOriginData还没改变,暂存了一个字段
|
isDesensitive: !this.tmpIsShowOriginData, // 发起请求的时候,isShowOriginData还没改变,暂存了一个字段
|
||||||
});
|
})
|
||||||
|
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
const listHead = this.formatHead(res.data.listHead);
|
const listHead = this.formatHead(res.data.listHead)
|
||||||
this.tableData = { ...res.data, listHead };
|
this.tableData = { ...res.data, listHead }
|
||||||
this.mainTableLoading = false;
|
this.mainTableLoading = false
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.$message.error('查询回收数据失败,请重试');
|
this.$message.error('查询回收数据失败,请重试')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleCurrentChange(current) {
|
handleCurrentChange(current) {
|
||||||
if (this.mainTableLoading) {
|
if (this.mainTableLoading) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
this.currentPage = current;
|
this.currentPage = current
|
||||||
this.init();
|
this.init()
|
||||||
},
|
},
|
||||||
formatHead(listHead = []) {
|
formatHead(listHead = []) {
|
||||||
const head = [];
|
const head = []
|
||||||
|
|
||||||
listHead.forEach((headItem) => {
|
listHead.forEach((headItem) => {
|
||||||
head.push({
|
head.push({
|
||||||
field: headItem.field,
|
field: headItem.field,
|
||||||
title: headItem.title,
|
title: headItem.title,
|
||||||
});
|
})
|
||||||
|
|
||||||
if (headItem.othersCode?.length) {
|
if (headItem.othersCode?.length) {
|
||||||
headItem.othersCode.forEach((item) => {
|
headItem.othersCode.forEach((item) => {
|
||||||
head.push({
|
head.push({
|
||||||
field: item.code,
|
field: item.code,
|
||||||
title: `${headItem.title}-${item.option}`,
|
title: `${headItem.title}-${item.option}`,
|
||||||
});
|
})
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
return head;
|
return head
|
||||||
},
|
},
|
||||||
async onIsShowOriginChange(data) {
|
async onIsShowOriginChange(data) {
|
||||||
if (this.mainTableLoading) {
|
if (this.mainTableLoading) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
// console.log(data)
|
// console.log(data)
|
||||||
this.tmpIsShowOriginData = data;
|
this.tmpIsShowOriginData = data
|
||||||
await this.init();
|
await this.init()
|
||||||
this.isShowOriginData = data;
|
this.isShowOriginData = data
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -132,7 +132,7 @@ export default {
|
|||||||
empty,
|
empty,
|
||||||
leftMenu,
|
leftMenu,
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@ -166,7 +166,7 @@ export default {
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
|
||||||
|
|
||||||
::v-deep .el-pagination {
|
:deep(.el-pagination) {
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
|
@ -14,14 +14,12 @@
|
|||||||
<el-input
|
<el-input
|
||||||
v-model="form.title"
|
v-model="form.title"
|
||||||
:class="form.title ? 'nonempty' : 'empty'"
|
:class="form.title ? 'nonempty' : 'empty'"
|
||||||
size="small"
|
|
||||||
placeholder="请输入问卷名称"
|
placeholder="请输入问卷名称"
|
||||||
/>
|
/>
|
||||||
<p class="form-item-tip">该标题可在打开问卷的浏览器顶部展示</p>
|
<p class="form-item-tip">该标题可在打开问卷的浏览器顶部展示</p>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item prop="remark" label="问卷备注">
|
<el-form-item prop="remark" label="问卷备注">
|
||||||
<el-input
|
<el-input
|
||||||
size="small"
|
|
||||||
v-model="form.remark"
|
v-model="form.remark"
|
||||||
:class="form.remark ? 'nonempty' : 'empty'"
|
:class="form.remark ? 'nonempty' : 'empty'"
|
||||||
placeholder="请输入备注"
|
placeholder="请输入备注"
|
||||||
@ -32,7 +30,6 @@
|
|||||||
<el-button
|
<el-button
|
||||||
class="create-btn"
|
class="create-btn"
|
||||||
type="primary"
|
type="primary"
|
||||||
size="small"
|
|
||||||
@click="submit"
|
@click="submit"
|
||||||
:loading="!canSubmit"
|
:loading="!canSubmit"
|
||||||
>
|
>
|
||||||
@ -42,9 +39,10 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { SURVEY_TYPE_LIST } from '../types';
|
import { SURVEY_TYPE_LIST } from '../types'
|
||||||
import { createSurvey } from '@/management/api/survey';
|
import { createSurvey } from '@/management/api/survey'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'CreateForm',
|
name: 'CreateForm',
|
||||||
@ -64,55 +62,56 @@ export default {
|
|||||||
title: '问卷调研',
|
title: '问卷调研',
|
||||||
remark: '问卷调研',
|
remark: '问卷调研',
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
SURVEY_TYPE_LIST() {
|
SURVEY_TYPE_LIST() {
|
||||||
return SURVEY_TYPE_LIST;
|
return SURVEY_TYPE_LIST
|
||||||
},
|
},
|
||||||
title() {
|
title() {
|
||||||
return this.SURVEY_TYPE_LIST.find((item) => item.type === this.selectType)
|
return this.SURVEY_TYPE_LIST.find((item) => item.type === this.selectType)
|
||||||
?.title;
|
?.title
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
checkForm(fn) {
|
checkForm(fn) {
|
||||||
this.$refs.ruleForm.validate((valid) => {
|
this.$refs.ruleForm.validate((valid) => {
|
||||||
valid && typeof fn === 'function' && fn();
|
valid && typeof fn === 'function' && fn()
|
||||||
});
|
})
|
||||||
},
|
},
|
||||||
submit() {
|
submit() {
|
||||||
if (!this.canSubmit) {
|
if (!this.canSubmit) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
this.checkForm(async () => {
|
this.checkForm(async () => {
|
||||||
const { selectType } = this;
|
const { selectType } = this
|
||||||
if (!this.canSubmit) {
|
if (!this.canSubmit) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
this.canSubmit = false;
|
this.canSubmit = false
|
||||||
const res = await createSurvey({
|
const res = await createSurvey({
|
||||||
surveyType: selectType,
|
surveyType: selectType,
|
||||||
...this.form,
|
...this.form,
|
||||||
});
|
})
|
||||||
if (res.code === 200 && res?.data?.id) {
|
if (res.code === 200 && res?.data?.id) {
|
||||||
const id = res.data.id;
|
const id = res.data.id
|
||||||
this.$router.push({
|
this.$router.push({
|
||||||
name: 'QuestionEditIndex',
|
name: 'QuestionEditIndex',
|
||||||
params: {
|
params: {
|
||||||
id,
|
id,
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
} else {
|
} else {
|
||||||
this.$message.error(res.errmsg || '创建失败');
|
this.$message.error(res.errmsg || '创建失败')
|
||||||
}
|
}
|
||||||
|
|
||||||
this.canSubmit = true;
|
this.canSubmit = true
|
||||||
});
|
})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" rel="stylesheet/scss" scoped>
|
<style lang="scss" rel="stylesheet/scss" scoped>
|
||||||
.right-side {
|
.right-side {
|
||||||
width: 538px;
|
width: 538px;
|
||||||
@ -142,7 +141,7 @@ export default {
|
|||||||
border: unset;
|
border: unset;
|
||||||
color: white;
|
color: white;
|
||||||
|
|
||||||
::v-deep span {
|
:deep(span) {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
@ -20,20 +21,21 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
img: '/imgs/s-logo.webp',
|
img: '/imgs/s-logo.webp',
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
toHomePage() {
|
toHomePage() {
|
||||||
this.$router.replace({
|
this.$router.replace({
|
||||||
name: 'survey',
|
name: 'survey',
|
||||||
});
|
})
|
||||||
},
|
},
|
||||||
onBack() {
|
onBack() {
|
||||||
this.$router.go(-1);
|
this.$router.go(-1)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" rel="stylesheet/scss" scoped>
|
<style lang="scss" rel="stylesheet/scss" scoped>
|
||||||
.nav-header {
|
.nav-header {
|
||||||
z-index: 99;
|
z-index: 99;
|
||||||
|
@ -23,10 +23,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
|
||||||
import NavHeader from './navHeader';
|
|
||||||
|
|
||||||
import { SURVEY_TYPE_LIST } from '../types';
|
<script>
|
||||||
|
import NavHeader from './navHeader.vue'
|
||||||
|
|
||||||
|
import { SURVEY_TYPE_LIST } from '../types'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'LeftSide',
|
name: 'LeftSide',
|
||||||
@ -41,17 +42,18 @@ export default {
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
renderData() {
|
renderData() {
|
||||||
return SURVEY_TYPE_LIST;
|
return SURVEY_TYPE_LIST
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
handleSelectType(key, value) {
|
handleSelectType(key, value) {
|
||||||
const { type } = value;
|
const { type } = value
|
||||||
this.$emit('selectTypeChange', type);
|
this.$emit('selectTypeChange', type)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" rel="stylesheet/scss" scoped>
|
<style lang="scss" rel="stylesheet/scss" scoped>
|
||||||
.left-side {
|
.left-side {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
@ -7,9 +7,10 @@
|
|||||||
<create-form :selectType="selectType" />
|
<create-form :selectType="selectType" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import typeList from './components/typeList';
|
import typeList from './components/typeList.vue'
|
||||||
import createForm from './components/createForm';
|
import createForm from './components/createForm.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'createPage',
|
name: 'createPage',
|
||||||
@ -20,15 +21,16 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
selectType: 'normal',
|
selectType: 'normal',
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onSelectTypeChange(selectType) {
|
onSelectTypeChange(selectType) {
|
||||||
this.selectType = selectType;
|
this.selectType = selectType
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" rel="stylesheet/scss" scoped>
|
<style lang="scss" rel="stylesheet/scss" scoped>
|
||||||
.new {
|
.new {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
@ -23,4 +23,4 @@ export const SURVEY_TYPE_LIST = [
|
|||||||
img: '/imgs/create/register-icon.webp',
|
img: '/imgs/create/register-icon.webp',
|
||||||
desc: '活动报名 / 会议报名',
|
desc: '活动报名 / 会议报名',
|
||||||
},
|
},
|
||||||
];
|
]
|
||||||
|
@ -1,29 +1,35 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<div class="nav" v-if="$slots.hasOwnProperty('nav')">
|
<div class="nav" v-if="slots.hasOwnProperty('nav')">
|
||||||
<slot name="nav"></slot>
|
<slot name="nav"></slot>
|
||||||
</div>
|
</div>
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<slot v-if="$slots.hasOwnProperty('body')" name="body"></slot>
|
<slot v-if="slots.hasOwnProperty('body')" name="body"></slot>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<div class="left" v-if="$slots.hasOwnProperty('left')">
|
<div class="left" v-if="slots.hasOwnProperty('left')">
|
||||||
<slot name="left"></slot>
|
<slot name="left"></slot>
|
||||||
</div>
|
</div>
|
||||||
<div class="center" v-if="$slots.hasOwnProperty('center')">
|
<div class="center" v-if="slots.hasOwnProperty('center')">
|
||||||
<slot name="center"></slot>
|
<slot name="center"></slot>
|
||||||
</div>
|
</div>
|
||||||
<div class="right" v-if="$slots.hasOwnProperty('right')">
|
<div class="right" v-if="slots.hasOwnProperty('right')">
|
||||||
<slot name="right"></slot>
|
<slot name="right"></slot>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
|
||||||
export default {
|
<script setup>
|
||||||
name: 'commonTemplate',
|
import { useSlots, useAttrs, getCurrentInstance } from 'vue'
|
||||||
};
|
|
||||||
|
const slots = useSlots()
|
||||||
|
const attrs = useAttrs()
|
||||||
|
const current = getCurrentInstance()
|
||||||
|
window.vm = current
|
||||||
|
console.log('current',current)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.main {
|
.main {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: 'LogoPreview',
|
name: 'LogoPreview',
|
||||||
@ -25,21 +26,22 @@ export default {
|
|||||||
isSelected: Boolean,
|
isSelected: Boolean,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {};
|
return {}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onSelect() {
|
onSelect() {
|
||||||
this.$emit('select');
|
this.$emit('select')
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
logoImg() {
|
logoImg() {
|
||||||
const { logoImage = {} } = this.logoConf;
|
const { logoImage } = this.logoConf
|
||||||
return logoImage;
|
return logoImage
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" rel="stylesheet/scss" scoped>
|
<style lang="scss" rel="stylesheet/scss" scoped>
|
||||||
.container {
|
.container {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -2,19 +2,20 @@
|
|||||||
<div class="title-wrapper" @click="handleClick()">
|
<div class="title-wrapper" @click="handleClick()">
|
||||||
<div class="main-title" :class="{ active: isSelected }" >
|
<div class="main-title" :class="{ active: isSelected }" >
|
||||||
<richEditor
|
<richEditor
|
||||||
:value="bannerConf?.titleConfig?.mainTitle"
|
:modelValue="bannerConf?.titleConfig?.mainTitle"
|
||||||
@input="onTitleInput"
|
@input="onTitleInput"
|
||||||
></richEditor>
|
></richEditor>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import richEditor from '@/common/Editor/RichEditor';
|
import richEditor from '@/common/Editor/RichEditor.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'mainTitlePreview',
|
name: 'mainTitlePreview',
|
||||||
data() {
|
data() {
|
||||||
return {};
|
return {}
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
preview: {
|
preview: {
|
||||||
@ -31,27 +32,24 @@ export default {
|
|||||||
computed: {},
|
computed: {},
|
||||||
methods: {
|
methods: {
|
||||||
handleClick() {
|
handleClick() {
|
||||||
if(this.preview) {
|
this.$emit('select')
|
||||||
return false
|
|
||||||
} else {
|
|
||||||
this.$emit('select');
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
onTitleInput(val) {
|
onTitleInput(val) {
|
||||||
if (!this.isSelected) {
|
if (!this.isSelected) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
this.$emit('change', {
|
this.$emit('change', {
|
||||||
key: 'titleConfig.mainTitle',
|
key: 'titleConfig.mainTitle',
|
||||||
value: val,
|
value: val,
|
||||||
});
|
})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
richEditor,
|
richEditor,
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" rel="stylesheet/scss" scoped>
|
<style lang="scss" rel="stylesheet/scss" scoped>
|
||||||
.title-wrapper {
|
.title-wrapper {
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
@ -65,7 +63,7 @@ export default {
|
|||||||
background-color: #f6f7f9;
|
background-color: #f6f7f9;
|
||||||
box-shadow: 0 0 5px #dedede;
|
box-shadow: 0 0 5px #dedede;
|
||||||
|
|
||||||
::v-deep .w-e-text-container {
|
:deep(.w-e-text-container) {
|
||||||
background-color: #f6f7f9;
|
background-color: #f6f7f9;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,50 @@
|
|||||||
|
<template>
|
||||||
|
<draggable
|
||||||
|
:list="renderData"
|
||||||
|
:options="dragOptions"
|
||||||
|
:onEnd="checkEnd"
|
||||||
|
:move="checkMove"
|
||||||
|
itemKey="field"
|
||||||
|
>
|
||||||
|
<template #item="{ element, index }">
|
||||||
|
<questionWrapper
|
||||||
|
v-bind="$attrs"
|
||||||
|
:ref="`questionWrapper-${element.field}`"
|
||||||
|
:moduleConfig="element"
|
||||||
|
:qIndex="element.qIndex"
|
||||||
|
:indexNumber="element.indexNumber"
|
||||||
|
:isSelected="currentEditOne === index"
|
||||||
|
:isLast="index + 1 === questionDataList.length"
|
||||||
|
@select="handleSelect"
|
||||||
|
@changeSeq="handleChangeSeq"
|
||||||
|
>
|
||||||
|
<QuestionContainer
|
||||||
|
v-bind="$attrs"
|
||||||
|
:type="element.type"
|
||||||
|
:moduleConfig="element"
|
||||||
|
:indexNumber="element.indexNumber"
|
||||||
|
:isSelected="currentEditOne === index"
|
||||||
|
:readonly="true"
|
||||||
|
@select="handleSelect"
|
||||||
|
></QuestionContainer>
|
||||||
|
</questionWrapper>
|
||||||
|
</template>
|
||||||
|
</draggable>
|
||||||
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { computed, defineComponent, ref, getCurrentInstance } from 'vue';
|
import { computed, defineComponent, ref, getCurrentInstance, h } from 'vue'
|
||||||
import QuestionContainer from '@/materials/questions/widgets/QuestionContainer.jsx';
|
import QuestionContainer from '@/materials/questions/widgets/QuestionContainer.jsx'
|
||||||
import questionWrapper from './questionWrapper.vue';
|
import questionWrapper from './questionWrapper.vue'
|
||||||
import draggable from 'vuedraggable';
|
import draggable from 'vuedraggable'
|
||||||
import { filterQuestionPreviewData } from '@/management/utils/index';
|
import { filterQuestionPreviewData } from '@/management/utils/index'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: '',
|
components: {
|
||||||
components: { draggable },
|
draggable,
|
||||||
|
questionWrapper,
|
||||||
|
QuestionContainer,
|
||||||
|
},
|
||||||
props: {
|
props: {
|
||||||
currentEditOne: {
|
currentEditOne: {
|
||||||
type: [Number, String],
|
type: [Number, String],
|
||||||
@ -16,41 +53,40 @@ export default defineComponent({
|
|||||||
questionDataList: {
|
questionDataList: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => {
|
default: () => {
|
||||||
return [];
|
return []
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
watch: {},
|
|
||||||
setup(props, { emit }) {
|
setup(props, { emit }) {
|
||||||
const renderData = computed(() => {
|
const renderData = computed(() => {
|
||||||
return filterQuestionPreviewData(props.questionDataList);
|
return filterQuestionPreviewData(props.questionDataList)
|
||||||
});
|
})
|
||||||
const handleSelect = (index) => {
|
const handleSelect = (index) => {
|
||||||
emit('select', index);
|
emit('select', index)
|
||||||
};
|
}
|
||||||
const handleChangeSeq = (data) => {
|
const handleChangeSeq = (data) => {
|
||||||
emit('changeSeq', data);
|
emit('changeSeq', data)
|
||||||
};
|
}
|
||||||
|
|
||||||
const isMoving = ref(false);
|
const isMoving = ref(false)
|
||||||
|
|
||||||
const checkMove = () => {
|
const checkMove = () => {
|
||||||
isMoving.value = true;
|
isMoving.value = true
|
||||||
};
|
}
|
||||||
|
|
||||||
const checkEnd = ({ oldIndex, newIndex }) => {
|
const checkEnd = ({ oldIndex, newIndex }) => {
|
||||||
emit('changeSeq', {
|
emit('changeSeq', {
|
||||||
type: 'move',
|
type: 'move',
|
||||||
index: oldIndex,
|
index: oldIndex,
|
||||||
range: newIndex - oldIndex,
|
range: newIndex - oldIndex,
|
||||||
});
|
})
|
||||||
};
|
}
|
||||||
|
|
||||||
const instance = getCurrentInstance();
|
const instance = getCurrentInstance()
|
||||||
|
|
||||||
const getQuestionRefByField = (field) => {
|
const getQuestionRefByField = (field) => {
|
||||||
return instance?.proxy?.$refs[`questionWrapper-${field}`] || null;
|
return instance?.proxy?.$refs[`questionWrapper-${field}`] || null
|
||||||
};
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
renderData,
|
renderData,
|
||||||
@ -68,54 +104,7 @@ export default defineComponent({
|
|||||||
forceFallback: true,
|
forceFallback: true,
|
||||||
},
|
},
|
||||||
getQuestionRefByField,
|
getQuestionRefByField,
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
render(h) {
|
})
|
||||||
return (
|
|
||||||
<draggable
|
|
||||||
list={this.renderData}
|
|
||||||
options={this.dragOptions}
|
|
||||||
onEnd={this.checkEnd}
|
|
||||||
move={this.checkMove}
|
|
||||||
>
|
|
||||||
{this.renderData.map((item, index) => {
|
|
||||||
return h(
|
|
||||||
questionWrapper,
|
|
||||||
{
|
|
||||||
ref: `questionWrapper-${item.field}`,
|
|
||||||
key: item.field,
|
|
||||||
props: {
|
|
||||||
moduleConfig: item,
|
|
||||||
qIndex: item.qIndex,
|
|
||||||
indexNumber: item.indexNumber,
|
|
||||||
isSelected: this.currentEditOne === index,
|
|
||||||
isLast: index + 1 === this.questionDataList.length,
|
|
||||||
},
|
|
||||||
on: {
|
|
||||||
...this.$listeners,
|
|
||||||
select: this.handleSelect,
|
|
||||||
changeSeq: this.handleChangeSeq,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
[
|
|
||||||
h(QuestionContainer, {
|
|
||||||
props: {
|
|
||||||
type: item.type,
|
|
||||||
moduleConfig: item,
|
|
||||||
indexNumber: item.indexNumber,
|
|
||||||
isSelected: this.currentEditOne === index,
|
|
||||||
readonly: true,
|
|
||||||
},
|
|
||||||
on: {
|
|
||||||
...this.$listeners,
|
|
||||||
select: this.handleSelect,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</draggable>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -16,14 +16,14 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import back from '../modules/generalModule/back.vue';
|
import back from '../modules/generalModule/back.vue'
|
||||||
import pageTitle from '../modules/generalModule/pageTitle.vue';
|
import pageTitle from '../modules/generalModule/pageTitle.vue'
|
||||||
import pageNav from '../modules/generalModule/pageNav.vue';
|
import pageNav from '../modules/generalModule/pageNav.vue'
|
||||||
import history from '../modules/contentModule/history.vue';
|
import history from '../modules/contentModule/history.vue'
|
||||||
import save from '../modules/contentModule/save.vue';
|
import save from '../modules/contentModule/save.vue'
|
||||||
import publish from '../modules/contentModule/publish.vue';
|
import publish from '../modules/contentModule/publish.vue'
|
||||||
import { mapState } from 'vuex';
|
import { mapState } from 'vuex'
|
||||||
import { get as _get } from 'lodash-es';
|
import { get as _get } from 'lodash-es'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'navbar',
|
name: 'navbar',
|
||||||
@ -36,14 +36,14 @@ export default {
|
|||||||
publish,
|
publish,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {};
|
return {}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState({
|
...mapState({
|
||||||
title: (state) => _get(state, 'edit.schema.metaData.title'),
|
title: (state) => _get(state, 'edit.schema.metaData.title'),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<script>
|
<script lang="jsx">
|
||||||
import {
|
import {
|
||||||
defineComponent,
|
defineComponent,
|
||||||
reactive,
|
reactive,
|
||||||
@ -6,6 +6,7 @@ import {
|
|||||||
computed,
|
computed,
|
||||||
getCurrentInstance,
|
getCurrentInstance,
|
||||||
} from 'vue';
|
} from 'vue';
|
||||||
|
import { Rank, Top, Bottom, CopyDocument, Delete } from '@element-plus/icons-vue'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'QuestionWrapper',
|
name: 'QuestionWrapper',
|
||||||
@ -119,6 +120,7 @@ export default defineComponent({
|
|||||||
// })
|
// })
|
||||||
// state.isHover = false
|
// state.isHover = false
|
||||||
// }
|
// }
|
||||||
|
const onMove = () => {}
|
||||||
return {
|
return {
|
||||||
...toRefs(state),
|
...toRefs(state),
|
||||||
itemClass,
|
itemClass,
|
||||||
@ -127,6 +129,7 @@ export default defineComponent({
|
|||||||
showDown,
|
showDown,
|
||||||
showCopy,
|
showCopy,
|
||||||
onCopy,
|
onCopy,
|
||||||
|
onMove,
|
||||||
onMoveUp,
|
onMoveUp,
|
||||||
onMoveDown,
|
onMoveDown,
|
||||||
onDelete,
|
onDelete,
|
||||||
@ -148,36 +151,46 @@ export default defineComponent({
|
|||||||
onClick={this.clickFormItem}
|
onClick={this.clickFormItem}
|
||||||
>
|
>
|
||||||
{this.moduleConfig.type !== 'section' && (
|
{this.moduleConfig.type !== 'section' && (
|
||||||
<div>{this.$slots.default}</div>
|
<div>{this.$slots.default()}</div>
|
||||||
)}
|
)}
|
||||||
{
|
{
|
||||||
<div class={[showHover ? 'visibily' : 'hidden', 'hoverItem']}>
|
<div class={[showHover ? 'visibily' : 'hidden', 'hoverItem']}>
|
||||||
<div
|
<div
|
||||||
class="item move el-icon-rank"
|
class="item"
|
||||||
vOn:click_stop_prevent={this.onMove}
|
onClickPrevent={this.onMove}
|
||||||
></div>
|
>
|
||||||
|
<el-icon><Rank /></el-icon>
|
||||||
|
</div>
|
||||||
{showUp && (
|
{showUp && (
|
||||||
<div
|
<div
|
||||||
class="item iconfont icon-shangyi"
|
class="item"
|
||||||
vOn:click_stop_prevent={this.onMoveUp}
|
onClickPrevent={this.onMoveUp}
|
||||||
></div>
|
>
|
||||||
|
<el-icon><Top /></el-icon>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
{showDown && (
|
{showDown && (
|
||||||
<div
|
<div
|
||||||
class="item iconfont icon-xiayi"
|
class="item"
|
||||||
vOn:click_stop_prevent={this.onMoveDown}
|
onClickPrevent={this.onMoveDown}
|
||||||
></div>
|
>
|
||||||
|
<el-icon><Bottom /></el-icon>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
{showCopy && (
|
{showCopy && (
|
||||||
<div
|
<div
|
||||||
class="item copy iconfont icon-fuzhi"
|
class="item"
|
||||||
vOn:click_stop_prevent={this.onCopy}
|
onClickPrevent={this.onCopy}
|
||||||
></div>
|
>
|
||||||
|
<el-icon><CopyDocument /></el-icon>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
<div
|
<div
|
||||||
class="item iconfont icon-shanchu"
|
class="item"
|
||||||
vOn:click_stop_prevent={this.onDelete}
|
onClickPrevent={this.onDelete}
|
||||||
></div>
|
>
|
||||||
|
<el-icon><Delete /></el-icon>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
@ -193,9 +206,9 @@ export default defineComponent({
|
|||||||
&.spliter {
|
&.spliter {
|
||||||
border-bottom: 0.12rem solid $spliter-color;
|
border-bottom: 0.12rem solid $spliter-color;
|
||||||
}
|
}
|
||||||
&:last-child{
|
// &:last-child{
|
||||||
border: none;
|
// border: none;
|
||||||
}
|
// }
|
||||||
.editor {
|
.editor {
|
||||||
display: flex;
|
display: flex;
|
||||||
font-size: 0.32rem;
|
font-size: 0.32rem;
|
||||||
@ -276,8 +289,10 @@ export default defineComponent({
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.item {
|
.item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
display: inline-block;
|
|
||||||
width: 28px;
|
width: 28px;
|
||||||
height: 28px;
|
height: 28px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-form
|
<el-form
|
||||||
class="config-form"
|
class="config-form"
|
||||||
size="small"
|
|
||||||
:labelPosition="labelPosition"
|
:labelPosition="labelPosition"
|
||||||
label-width="110px"
|
label-width="110px"
|
||||||
:inline="inline"
|
:inline="inline"
|
||||||
@submit.native.prevent
|
@submit.native.prevent
|
||||||
>
|
>
|
||||||
<template v-for="(item, index) in formFieldData">
|
<template v-for="(item, index) in formFieldData" :key="item.key + index">
|
||||||
<FormItem :key="item.key + index" class="form-item" :form-config="item">
|
<FormItem class="form-item" :form-config="item">
|
||||||
<template v-if="item.type === 'Customed'">
|
<template v-if="item.type === 'Customed'">
|
||||||
<SettersField
|
<SettersField
|
||||||
:key="index"
|
:key="index"
|
||||||
@ -32,35 +31,32 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-form>
|
</el-form>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {
|
import { get as _get, pick as _pick, isFunction as _isFunction } from 'lodash-es'
|
||||||
get as _get,
|
|
||||||
pick as _pick,
|
|
||||||
isFunction as _isFunction,
|
|
||||||
} from 'lodash-es';
|
|
||||||
|
|
||||||
import FormItem from '@/materials/setters/widgets/FormItem.vue';
|
import FormItem from '@/materials/setters/widgets/FormItem.vue'
|
||||||
import setterLoader from '@/materials/setters/setterLoader';
|
import setterLoader from '@/materials/setters/setterLoader'
|
||||||
|
|
||||||
import { FORM_CHANGE_EVENT_KEY } from '@/materials/setters/constant';
|
import { FORM_CHANGE_EVENT_KEY } from '@/materials/setters/constant'
|
||||||
|
|
||||||
const formatValue = ({ item, moduleConfig }) => {
|
const formatValue = ({ item, moduleConfig }) => {
|
||||||
if (_isFunction(item.valueAdapter)) {
|
if (_isFunction(item.valueAdapter)) {
|
||||||
const value = item.valueAdapter({ moduleConfig });
|
const value = item.valueAdapter({ moduleConfig })
|
||||||
return value;
|
return value
|
||||||
} else {
|
} else {
|
||||||
const { key, keys } = item;
|
const { key, keys } = item
|
||||||
|
|
||||||
let result = null;
|
let result = null
|
||||||
if (key) {
|
if (key) {
|
||||||
result = _get(moduleConfig, key, item.value);
|
result = _get(moduleConfig, key, item.value)
|
||||||
}
|
}
|
||||||
if (keys) {
|
if (keys) {
|
||||||
result = _pick(moduleConfig, keys);
|
result = _pick(moduleConfig, keys)
|
||||||
}
|
}
|
||||||
return result;
|
return result
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'SettersField',
|
name: 'SettersField',
|
||||||
@ -79,7 +75,7 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
registerd: {},
|
registerd: {},
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
FormItem,
|
FormItem,
|
||||||
@ -89,25 +85,25 @@ export default {
|
|||||||
return this.formConfigList
|
return this.formConfigList
|
||||||
.filter((item) => {
|
.filter((item) => {
|
||||||
if (!item.type) {
|
if (!item.type) {
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
if (item.type !== 'Customed' && !this.registerd[item.type]) {
|
if (item.type !== 'Customed' && !this.registerd[item.type]) {
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
if (item.hidden) {
|
if (item.hidden) {
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
if (_isFunction(item.relyFunc)) {
|
if (_isFunction(item.relyFunc)) {
|
||||||
return item.relyFunc(this.moduleConfig);
|
return item.relyFunc(this.moduleConfig)
|
||||||
}
|
}
|
||||||
return true;
|
return true
|
||||||
})
|
})
|
||||||
.map((item) => {
|
.map((item) => {
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
value: formatValue({ item, moduleConfig: this.moduleConfig }),
|
value: formatValue({ item, moduleConfig: this.moduleConfig }),
|
||||||
};
|
}
|
||||||
});
|
})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@ -116,61 +112,62 @@ export default {
|
|||||||
immediate: true,
|
immediate: true,
|
||||||
handler(newVal) {
|
handler(newVal) {
|
||||||
if (!newVal || !newVal.length) {
|
if (!newVal || !newVal.length) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
this.handleComponentRegister(newVal);
|
this.handleComponentRegister(newVal)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async handleComponentRegister(formFieldData) {
|
async handleComponentRegister(formFieldData) {
|
||||||
const setters = formFieldData.map((item) => item.type);
|
const setters = formFieldData.map((item) => item.type)
|
||||||
const settersSet = new Set(setters);
|
const settersSet = new Set(setters)
|
||||||
const settersArr = Array.from(settersSet);
|
const settersArr = Array.from(settersSet)
|
||||||
const allSetters = settersArr.map((item) => {
|
const allSetters = settersArr.map((item) => {
|
||||||
return {
|
return {
|
||||||
type: item,
|
type: item,
|
||||||
path: item,
|
path: item,
|
||||||
};
|
}
|
||||||
});
|
})
|
||||||
try {
|
try {
|
||||||
const comps = await setterLoader.loadComponents(allSetters);
|
const comps = await setterLoader.loadComponents(allSetters)
|
||||||
for (const comp of comps) {
|
for (const comp of comps) {
|
||||||
if (!comp) {
|
if (!comp) {
|
||||||
continue;
|
continue
|
||||||
}
|
}
|
||||||
const { type, component, err } = comp;
|
const { type, component, err } = comp
|
||||||
if (!err) {
|
if (!err) {
|
||||||
const componentName = component.name;
|
const componentName = component.name
|
||||||
if (!this.$options.components) {
|
if (!this.$options.components) {
|
||||||
this.$options.components = {};
|
this.$options.components = {}
|
||||||
}
|
}
|
||||||
this.$options.components[componentName] = component;
|
this.$options.components[componentName] = component
|
||||||
this.$set(this.registerd, type, componentName);
|
this.registerd[type] = componentName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onFormChange(data, formConfig) {
|
onFormChange(data, formConfig) {
|
||||||
if (_isFunction(formConfig?.setterAdapter)) {
|
if (_isFunction(formConfig?.setterAdapter)) {
|
||||||
const resultData = formConfig.setterAdapter(data);
|
const resultData = formConfig.setterAdapter(data)
|
||||||
if (Array.isArray(resultData)) {
|
if (Array.isArray(resultData)) {
|
||||||
resultData.forEach((item) => {
|
resultData.forEach((item) => {
|
||||||
this.$emit(FORM_CHANGE_EVENT_KEY, item);
|
this.$emit(FORM_CHANGE_EVENT_KEY, item)
|
||||||
});
|
})
|
||||||
} else {
|
} else {
|
||||||
this.$emit(FORM_CHANGE_EVENT_KEY, resultData);
|
this.$emit(FORM_CHANGE_EVENT_KEY, resultData)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.$emit(FORM_CHANGE_EVENT_KEY, data);
|
this.$emit(FORM_CHANGE_EVENT_KEY, data)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" rel="stylesheet/scss" scoped>
|
<style lang="scss" rel="stylesheet/scss" scoped>
|
||||||
.config-form {
|
.config-form {
|
||||||
padding: 15px 0;
|
padding: 15px 0;
|
||||||
@ -178,11 +175,11 @@ export default {
|
|||||||
.nps-customed-config {
|
.nps-customed-config {
|
||||||
.el-form-item {
|
.el-form-item {
|
||||||
margin-right: 0px;
|
margin-right: 0px;
|
||||||
::v-deep .el-form-item__label {
|
:deep(.el-form-item__label) {
|
||||||
width: 70px !important;
|
width: 70px !important;
|
||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
}
|
}
|
||||||
::v-deep .el-input__inner {
|
:deep(.el-input__inner) {
|
||||||
width: 234px;
|
width: 234px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,11 +11,12 @@
|
|||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: 'Submit',
|
name: 'Submit',
|
||||||
data() {
|
data() {
|
||||||
return {};
|
return {}
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
submitConf: Object,
|
submitConf: Object,
|
||||||
@ -27,11 +28,12 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onClick() {
|
onClick() {
|
||||||
this.$emit('select');
|
this.$emit('select')
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" rel="stylesheet/scss" scoped>
|
<style lang="scss" rel="stylesheet/scss" scoped>
|
||||||
.submit-wrapper {
|
.submit-wrapper {
|
||||||
padding: 25px;
|
padding: 25px;
|
||||||
|
@ -3,17 +3,21 @@
|
|||||||
<leftMenu class="left"></leftMenu>
|
<leftMenu class="left"></leftMenu>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<commonTemplate style="background-color: #f6f7f9">
|
<commonTemplate style="background-color: #f6f7f9">
|
||||||
<navbar class="navbar" slot="nav"></navbar>
|
<template #nav>
|
||||||
<router-view slot="body"></router-view>
|
<navbar class="navbar"></navbar>
|
||||||
|
</template>
|
||||||
|
<template #body>
|
||||||
|
<router-view></router-view>
|
||||||
|
</template>
|
||||||
</commonTemplate>
|
</commonTemplate>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import commonTemplate from './components/commonTemplate.vue';
|
import commonTemplate from './components/commonTemplate.vue'
|
||||||
import navbar from './components/navbar.vue';
|
import navbar from './components/navbar.vue'
|
||||||
import leftMenu from '@/management/components/leftMenu.vue';
|
import leftMenu from '@/management/components/leftMenu.vue'
|
||||||
export default {
|
export default {
|
||||||
name: 'questionEditPage',
|
name: 'questionEditPage',
|
||||||
components: {
|
components: {
|
||||||
@ -22,21 +26,23 @@ export default {
|
|||||||
leftMenu,
|
leftMenu,
|
||||||
},
|
},
|
||||||
async created() {
|
async created() {
|
||||||
this.$store.commit('edit/setSurveyId', this.$route.params.id);
|
this.$store.commit('edit/setSurveyId', this.$route.params.id)
|
||||||
|
this.$store.dispatch('getBannerData')
|
||||||
try {
|
try {
|
||||||
await this.$store.dispatch('edit/init');
|
await this.$store.dispatch('edit/init')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.$message.error(error.message);
|
this.$message.error(error.message)
|
||||||
// 自动跳转回列表页
|
// 自动跳转回列表页
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.$router.replace({
|
this.$router.replace({
|
||||||
name: 'survey',
|
name: 'survey',
|
||||||
});
|
})
|
||||||
}, 1000);
|
}, 1000)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.edit-index {
|
.edit-index {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@ -56,6 +62,7 @@ export default {
|
|||||||
padding-left: 80px;
|
padding-left: 80px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar {
|
.navbar {
|
||||||
border-bottom: 1px solid #e7e9eb;
|
border-bottom: 1px solid #e7e9eb;
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { pick as _pick, get as _get } from 'lodash-es';
|
import { pick as _pick, get as _get } from 'lodash-es'
|
||||||
|
|
||||||
// 生成需要保存到接口的数据
|
// 生成需要保存到接口的数据
|
||||||
export default function (schema) {
|
export default function (schema) {
|
||||||
const surveyId = _get(schema, 'metaData._id');
|
const surveyId = _get(schema, 'metaData._id')
|
||||||
const configData = _pick(schema, [
|
const configData = _pick(schema, [
|
||||||
'bannerConf',
|
'bannerConf',
|
||||||
'baseConf',
|
'baseConf',
|
||||||
@ -10,13 +10,13 @@ export default function (schema) {
|
|||||||
'skinConf',
|
'skinConf',
|
||||||
'submitConf',
|
'submitConf',
|
||||||
'questionDataList',
|
'questionDataList',
|
||||||
]);
|
])
|
||||||
configData.dataConf = {
|
configData.dataConf = {
|
||||||
dataList: configData.questionDataList,
|
dataList: configData.questionDataList,
|
||||||
};
|
}
|
||||||
delete configData.questionDataList;
|
delete configData.questionDataList
|
||||||
return {
|
return {
|
||||||
surveyId,
|
surveyId,
|
||||||
configData,
|
configData,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,21 +22,22 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-popover>
|
</el-popover>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
|
||||||
import { getSurveyHistory } from '@/management/api/survey';
|
|
||||||
import moment from 'moment';
|
|
||||||
// 引入中文
|
|
||||||
import 'moment/locale/zh-cn';
|
|
||||||
// 设置中文
|
|
||||||
moment.locale('zh-cn');
|
|
||||||
|
|
||||||
import { mapState } from 'vuex';
|
<script>
|
||||||
import { get as _get } from 'lodash-es';
|
import { getSurveyHistory } from '@/management/api/survey'
|
||||||
|
import moment from 'moment'
|
||||||
|
// 引入中文
|
||||||
|
import 'moment/locale/zh-cn'
|
||||||
|
// 设置中文
|
||||||
|
moment.locale('zh-cn')
|
||||||
|
|
||||||
|
import { mapState } from 'vuex'
|
||||||
|
import { get as _get } from 'lodash-es'
|
||||||
|
|
||||||
const getItemData = (item) => ({
|
const getItemData = (item) => ({
|
||||||
operator: item?.operator?.username || '未知用户',
|
operator: item?.operator?.username || '未知用户',
|
||||||
time: moment(item.createDate).format('YYYY-MM-DD HH:mm:ss'),
|
time: moment(item.createDate).format('YYYY-MM-DD HH:mm:ss'),
|
||||||
});
|
})
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'history',
|
name: 'history',
|
||||||
@ -45,10 +46,10 @@ export default {
|
|||||||
surveyId: (state) => _get(state, 'edit.surveyId'),
|
surveyId: (state) => _get(state, 'edit.surveyId'),
|
||||||
}),
|
}),
|
||||||
dailyList() {
|
dailyList() {
|
||||||
return this.dailyHis.map(getItemData);
|
return this.dailyHis.map(getItemData)
|
||||||
},
|
},
|
||||||
publishList() {
|
publishList() {
|
||||||
return this.publishHis.map(getItemData);
|
return this.publishHis.map(getItemData)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
@ -57,7 +58,7 @@ export default {
|
|||||||
publishHis: [],
|
publishHis: [],
|
||||||
currentTab: 'daily',
|
currentTab: 'daily',
|
||||||
visible: false,
|
visible: false,
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
surveyId: {
|
surveyId: {
|
||||||
@ -73,25 +74,26 @@ export default {
|
|||||||
surveyId: this.surveyId,
|
surveyId: this.surveyId,
|
||||||
historyType: 'publishHis',
|
historyType: 'publishHis',
|
||||||
}),
|
}),
|
||||||
]);
|
])
|
||||||
this.dailyHis = dailyHis.data || [];
|
this.dailyHis = dailyHis.data || []
|
||||||
this.publishHis = publishHis.data || [];
|
this.publishHis = publishHis.data || []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onShow() {
|
onShow() {
|
||||||
this.visible = true;
|
this.visible = true
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import url('@/management/styles/edit-btn.scss');
|
@import url('@/management/styles/edit-btn.scss');
|
||||||
.custom-tab {
|
.custom-tab {
|
||||||
width: 300px;
|
width: 300px;
|
||||||
::v-deep .el-tabs__nav {
|
:deep(.el-tabs__nav) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
.el-tabs__item {
|
.el-tabs__item {
|
||||||
|
@ -8,17 +8,18 @@
|
|||||||
发布
|
发布
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState } from 'vuex';
|
import { mapState } from 'vuex'
|
||||||
import { publishSurvey, saveSurvey } from '@/management/api/survey';
|
import { publishSurvey, saveSurvey } from '@/management/api/survey'
|
||||||
import buildData from './buildData';
|
import buildData from './buildData'
|
||||||
import { get as _get } from 'lodash-es';
|
import { get as _get } from 'lodash-es'
|
||||||
export default {
|
export default {
|
||||||
name: 'publish',
|
name: 'publish',
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
isPublishing: false,
|
isPublishing: false,
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState({
|
...mapState({
|
||||||
@ -27,40 +28,41 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async onPublish() {
|
async onPublish() {
|
||||||
const saveData = buildData(this.$store.state.edit.schema);
|
const saveData = buildData(this.$store.state.edit.schema)
|
||||||
if (!saveData.surveyId) {
|
if (!saveData.surveyId) {
|
||||||
this.$message.error('未获取到问卷id');
|
this.$message.error('未获取到问卷id')
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
if (this.isPublishing) {
|
if (this.isPublishing) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
this.isPublishing = true;
|
this.isPublishing = true
|
||||||
const saveRes = await saveSurvey(saveData);
|
const saveRes = await saveSurvey(saveData)
|
||||||
if (saveRes.code !== 200) {
|
if (saveRes.code !== 200) {
|
||||||
this.$message.error(saveRes.errmsg || '问卷保存失败');
|
this.$message.error(saveRes.errmsg || '问卷保存失败')
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
const publishRes = await publishSurvey({ surveyId: this.surveyId });
|
const publishRes = await publishSurvey({ surveyId: this.surveyId })
|
||||||
if (publishRes.code === 200) {
|
if (publishRes.code === 200) {
|
||||||
this.$message.success('发布成功');
|
this.$message.success('发布成功')
|
||||||
this.$store.dispatch('edit/getSchemaFromRemote');
|
this.$store.dispatch('edit/getSchemaFromRemote')
|
||||||
this.$router.push({
|
this.$router.push({
|
||||||
name: 'publishResultPage',
|
name: 'publishResultPage',
|
||||||
});
|
})
|
||||||
} else {
|
} else {
|
||||||
this.$message.error(`发布失败 ${publishRes.errmsg}`);
|
this.$message.error(`发布失败 ${publishRes.errmsg}`)
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.$message.error(`发布失败`);
|
this.$message.error(`发布失败`)
|
||||||
} finally {
|
} finally {
|
||||||
this.isPublishing = false;
|
this.isPublishing = false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.publish-btn {
|
.publish-btn {
|
||||||
width: 100px;
|
width: 100px;
|
||||||
|
@ -7,29 +7,35 @@
|
|||||||
<span class="sv-text">
|
<span class="sv-text">
|
||||||
{{ saveText }}
|
{{ saveText }}
|
||||||
</span>
|
</span>
|
||||||
<i class="icon el-icon-loading" v-if="autoSaveStatus === 'saving'"></i>
|
<el-icon class="icon" v-if="autoSaveStatus === 'saving'"><el-icon-loading /></el-icon>
|
||||||
<i
|
<el-icon class="icon succeed" v-else-if="autoSaveStatus === 'succeed'"><el-icon-check /></el-icon>
|
||||||
class="icon succeed el-icon-check"
|
|
||||||
v-else-if="autoSaveStatus === 'succeed'"
|
|
||||||
></i>
|
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { saveSurvey } from '@/management/api/survey';
|
import {
|
||||||
import buildData from './buildData';
|
Loading as ElIconLoading,
|
||||||
import { mapState } from 'vuex';
|
Check as ElIconCheck,
|
||||||
import { get as _get } from 'lodash-es';
|
} from '@element-plus/icons-vue'
|
||||||
|
import { saveSurvey } from '@/management/api/survey'
|
||||||
|
import buildData from './buildData'
|
||||||
|
import { mapState } from 'vuex'
|
||||||
|
import { get as _get } from 'lodash-es'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
components: {
|
||||||
|
ElIconLoading,
|
||||||
|
ElIconCheck,
|
||||||
|
},
|
||||||
name: 'save',
|
name: 'save',
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
isSaving: false,
|
isSaving: false,
|
||||||
isShowAutoSave: false,
|
isShowAutoSave: false,
|
||||||
autoSaveStatus: 'succeed',
|
autoSaveStatus: 'succeed',
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState({
|
...mapState({
|
||||||
@ -40,13 +46,13 @@ export default {
|
|||||||
saving: '保存中',
|
saving: '保存中',
|
||||||
succeed: '保存成功',
|
succeed: '保存成功',
|
||||||
failed: '保存失败',
|
failed: '保存失败',
|
||||||
};
|
}
|
||||||
return statusMap[this.autoSaveStatus];
|
return statusMap[this.autoSaveStatus]
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
schemaUpdateTime() {
|
schemaUpdateTime() {
|
||||||
this.triggerAutoSave();
|
this.triggerAutoSave()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -54,68 +60,69 @@ export default {
|
|||||||
if (this.autoSaveStatus === 'saving') {
|
if (this.autoSaveStatus === 'saving') {
|
||||||
// 正在调用接口
|
// 正在调用接口
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.triggerAutoSave();
|
this.triggerAutoSave()
|
||||||
}, 1000);
|
}, 1000)
|
||||||
} else {
|
} else {
|
||||||
if (this.timer) {
|
if (this.timer) {
|
||||||
clearTimeout(this.timer);
|
clearTimeout(this.timer)
|
||||||
}
|
}
|
||||||
this.timer = setTimeout(() => {
|
this.timer = setTimeout(() => {
|
||||||
this.autoSaveStatus = 'saving';
|
this.autoSaveStatus = 'saving'
|
||||||
this.isShowAutoSave = true;
|
this.isShowAutoSave = true
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.saveData()
|
this.saveData()
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
this.autoSaveStatus = 'succeed';
|
this.autoSaveStatus = 'succeed'
|
||||||
} else {
|
} else {
|
||||||
this.autoSaveStatus = 'failed';
|
this.autoSaveStatus = 'failed'
|
||||||
}
|
}
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.isShowAutoSave = false;
|
this.isShowAutoSave = false
|
||||||
this.timer = null;
|
this.timer = null
|
||||||
}, 300);
|
}, 300)
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
this.timer = null;
|
this.timer = null
|
||||||
this.autoSaveStatus = 'failed';
|
this.autoSaveStatus = 'failed'
|
||||||
this.isShowAutoSave = true;
|
this.isShowAutoSave = true
|
||||||
});
|
})
|
||||||
});
|
})
|
||||||
}, 2000);
|
}, 2000)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async saveData() {
|
async saveData() {
|
||||||
const saveData = buildData(this.$store.state.edit.schema);
|
const saveData = buildData(this.$store.state.edit.schema)
|
||||||
if (!saveData.surveyId) {
|
if (!saveData.surveyId) {
|
||||||
this.$message.error('未获取到问卷id');
|
this.$message.error('未获取到问卷id')
|
||||||
return null;
|
return null
|
||||||
}
|
}
|
||||||
const res = await saveSurvey(saveData);
|
const res = await saveSurvey(saveData)
|
||||||
return res;
|
return res
|
||||||
},
|
},
|
||||||
async onSave() {
|
async onSave() {
|
||||||
if (this.isSaving) {
|
if (this.isSaving) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
this.isShowAutoSave = false;
|
this.isShowAutoSave = false
|
||||||
try {
|
try {
|
||||||
this.isSaving = true;
|
this.isSaving = true
|
||||||
const res = await this.saveData();
|
const res = await this.saveData()
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
this.$message.success('保存成功');
|
this.$message.success('保存成功')
|
||||||
} else {
|
} else {
|
||||||
this.$message.error(res.errmsg);
|
this.$message.error(res.errmsg)
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.$message.error('保存问卷失败');
|
this.$message.error('保存问卷失败')
|
||||||
} finally {
|
} finally {
|
||||||
this.isSaving = false;
|
this.isSaving = false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import url('@/management/styles/edit-btn.scss');
|
@import url('@/management/styles/edit-btn.scss');
|
||||||
|
|
||||||
|
@ -4,16 +4,18 @@
|
|||||||
<span>返回</span>
|
<span>返回</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: 'back',
|
name: 'back',
|
||||||
methods: {
|
methods: {
|
||||||
onBack() {
|
onBack() {
|
||||||
this.$router.go(-1);
|
this.$router.go(-1)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.back-btn {
|
.back-btn {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<template v-for="btnItem in btnList">
|
<template v-for="btnItem in btnList" :key="btnItem.key">
|
||||||
<router-link
|
<router-link
|
||||||
class="navbar-btn"
|
|
||||||
:key="btnItem.key"
|
|
||||||
:to="{ name: btnItem.router }"
|
:to="{ name: btnItem.router }"
|
||||||
tag="div"
|
tag="div"
|
||||||
replace
|
replace
|
||||||
@ -12,6 +10,7 @@
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
:class="[
|
:class="[
|
||||||
|
'navbar-btn',
|
||||||
(isActive && btnItem.key === 'skinsettings' ) || isExactActive ? 'router-link-exact-active' : '']"
|
(isActive && btnItem.key === 'skinsettings' ) || isExactActive ? 'router-link-exact-active' : '']"
|
||||||
>
|
>
|
||||||
<i class="iconfont" :class="[btnItem.icon]"></i>
|
<i class="iconfont" :class="[btnItem.icon]"></i>
|
||||||
@ -23,6 +22,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: 'pageNav',
|
name: 'pageNav',
|
||||||
@ -52,10 +52,11 @@ export default {
|
|||||||
next: true,
|
next: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.content {
|
.content {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
{{ title }}
|
{{ title }}
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: 'pageTitle',
|
name: 'pageTitle',
|
||||||
@ -12,8 +13,9 @@ export default {
|
|||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.title {
|
.title {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
@ -1,32 +1,33 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-tabs type="border-card" v-model="tabSelected" class="tab-box">
|
<el-tabs type="border-card" v-model="tabSelected" class="tab-box">
|
||||||
<el-tab-pane label="题型选择">
|
<el-tab-pane label="题型选择">
|
||||||
<type-list />
|
<TypeList />
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane label="题目大纲">
|
<el-tab-pane label="题目大纲">
|
||||||
<catalog />
|
<Catalog />
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import typeList from './components/typeList';
|
import TypeList from './components/typeList.vue'
|
||||||
import catalog from './components/catalog.vue';
|
import Catalog from './components/catalog.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'EditLeftTabPanel',
|
name: 'EditLeftTabPanel',
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
tabSelected: '0',
|
tabSelected: '0',
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
typeList,
|
TypeList,
|
||||||
catalog,
|
Catalog,
|
||||||
},
|
},
|
||||||
methods: {},
|
methods: {},
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" rel="stylesheet/scss" scoped>
|
<style lang="scss" rel="stylesheet/scss" scoped>
|
||||||
.tab-box {
|
.tab-box {
|
||||||
width: 300px;
|
width: 300px;
|
||||||
@ -34,10 +35,10 @@ export default {
|
|||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
border: none;
|
border: none;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
::v-deep .el-tabs__nav {
|
:deep(.el-tabs__nav) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
::v-deep .el-tabs__item {
|
:deep(.el-tabs__item) {
|
||||||
width: 50%;
|
width: 50%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,17 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="question-catalog-wrapper">
|
<div class="question-catalog-wrapper">
|
||||||
<draggable :list="renderData" :options="dragOptions" @end="onDragEnd">
|
<draggable
|
||||||
<template v-for="(catalogItem, index) in renderData">
|
:list="renderData"
|
||||||
|
@end="onDragEnd"
|
||||||
|
itemKey="field"
|
||||||
|
handle=".draggHandle"
|
||||||
|
host-class="catalog-item-ghost"
|
||||||
|
>
|
||||||
|
<template #item="{ element, index }">
|
||||||
<catalogItem
|
<catalogItem
|
||||||
:key="catalogItem.field"
|
:title="element.title"
|
||||||
:title="catalogItem.title"
|
:indexNumber="element.indexNumber"
|
||||||
:indexNumber="catalogItem.indexNumber"
|
:showIndex="element.showIndex"
|
||||||
:showIndex="catalogItem.showIndex"
|
|
||||||
@select="onSelect(index)"
|
@select="onSelect(index)"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
@ -15,27 +20,22 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import draggable from 'vuedraggable';
|
import draggable from 'vuedraggable'
|
||||||
import catalogItem from './catalogItem';
|
import catalogItem from './catalogItem.vue'
|
||||||
import { filterQuestionPreviewData } from '@/management/utils/index';
|
import { filterQuestionPreviewData } from '@/management/utils/index'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'QuestionCatalog',
|
name: 'QuestionCatalog',
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
dragOptions: {
|
}
|
||||||
handle: '.draggHandle',
|
|
||||||
ghostClass: 'catalog-item-ghost',
|
|
||||||
dragClass: 'catalog-item-dragging',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
questionDataList() {
|
questionDataList() {
|
||||||
return this.$store.state.edit.schema.questionDataList;
|
return this.$store.state.edit.schema.questionDataList
|
||||||
},
|
},
|
||||||
renderData() {
|
renderData() {
|
||||||
return filterQuestionPreviewData(this.questionDataList) || [];
|
return filterQuestionPreviewData(this.questionDataList) || []
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
@ -44,18 +44,19 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onDragEnd(data) {
|
onDragEnd(data) {
|
||||||
const { newIndex, oldIndex } = data;
|
const { newIndex, oldIndex } = data
|
||||||
this.$store.dispatch('edit/moveQuestion', {
|
this.$store.dispatch('edit/moveQuestion', {
|
||||||
index: oldIndex,
|
index: oldIndex,
|
||||||
range: newIndex - oldIndex,
|
range: newIndex - oldIndex,
|
||||||
});
|
})
|
||||||
},
|
},
|
||||||
onSelect(index) {
|
onSelect(index) {
|
||||||
this.$store.commit('edit/setCurrentEditOne', index);
|
this.$store.commit('edit/setCurrentEditOne', index)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" rel="stylesheet/scss" scoped>
|
<style lang="scss" rel="stylesheet/scss" scoped>
|
||||||
.question-catalog-wrapper {
|
.question-catalog-wrapper {
|
||||||
padding-bottom: 400px; // 考试题有个上拉框会盖住,改成和题型一致的
|
padding-bottom: 400px; // 考试题有个上拉框会盖住,改成和题型一致的
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
export default {
|
export default {
|
||||||
name: 'QuestionCatalogItem',
|
name: 'QuestionCatalogItem',
|
||||||
data() {
|
data() {
|
||||||
return {};
|
return {}
|
||||||
},
|
},
|
||||||
computed: {},
|
computed: {},
|
||||||
props: {
|
props: {
|
||||||
@ -32,11 +32,12 @@ export default {
|
|||||||
components: {},
|
components: {},
|
||||||
methods: {
|
methods: {
|
||||||
onSelect() {
|
onSelect() {
|
||||||
this.$emit('select');
|
this.$emit('select')
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" rel="stylesheet/scss" scoped>
|
<style lang="scss" rel="stylesheet/scss" scoped>
|
||||||
.question-catalog-item {
|
.question-catalog-item {
|
||||||
position: relative;
|
position: relative;
|
||||||
|