Merge remote-tracking branch 'origin/feature-sell-verify' into sit

This commit is contained in:
fanpeijiang
2022-10-23 19:11:03 +08:00
33 changed files with 3695 additions and 1274 deletions

BIN
.DS_Store vendored

Binary file not shown.

46
src/api/qc.js Normal file
View File

@@ -0,0 +1,46 @@
import request from '@/utils/request'
/* 标记答卷 */
export function answer_mark(params) {
return request({
url: `/console/surveys/${params.sn}/answer_mark`,
method: 'POST',
data: params
})
}
/* 处理无效答卷 */
export function nullDeal(params) {
return request({
url: `/console/surveys/${params.sn}/nullDeal`,
method: 'POST',
data: params
})
}
/* 批量更新标记数据 */
export function answer_mark_batch(params) {
return request({
url: `/console/surveys/${params.sn}/answer_mark_batch`,
method: 'POST',
data: params
})
}
/* 答卷标记取消 */
export function answer_mark_del(params) {
return request({
url: `/console/surveys/${params.sn}/answer_mark`,
method: 'DELETE',
data: params
})
}
/* 答卷标记取消 */
export function getNullDealConfig(params) {
return request({
url: `/console/surveys/${params.sn}/getNullDealConfig`,
method: 'GET',
params
})
}

View File

@@ -2592,9 +2592,9 @@
<pre><code class="language-css"
>@font-face {
font-family: 'iconfont';
src: url('iconfont.woff2?t=1666232085564') format('woff2'),
url('iconfont.woff?t=1666232085564') format('woff'),
url('iconfont.ttf?t=1666232085564') format('truetype');
src: url('iconfont.woff2?t=1666180463175') format('woff2'),
url('iconfont.woff?t=1666180463175') format('woff'),
url('iconfont.ttf?t=1666180463175') format('truetype');
}
</code></pre>
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>

View File

@@ -1,8 +1,8 @@
@font-face {
font-family: "iconfont"; /* Project id 3121635 */
src: url('iconfont.woff2?t=1666232085564') format('woff2'),
url('iconfont.woff?t=1666232085564') format('woff'),
url('iconfont.ttf?t=1666232085564') format('truetype');
src: url('iconfont.woff2?t=1666180463175') format('woff2'),
url('iconfont.woff?t=1666180463175') format('woff'),
url('iconfont.ttf?t=1666180463175') format('truetype');
}
.iconfont {

View File

@@ -1,12 +1,10 @@
import { createRouter, createWebHashHistory } from "vue-router";
import routes from "./modules";
import ProjectManage from "./router.projectManage";
import TemplateMarket from "./route.templateMarket"
import Contact from "./route.contact";
import DocumentLibrary from "./route.documentLibrary";
import DataStatistics from "./route.datastatistics";
import { createRouter, createWebHashHistory } from 'vue-router'
import routes from './modules'
import ProjectManage from './router.projectManage'
import TemplateMarket from './route.templateMarket'
import Contact from './route.contact'
import DocumentLibrary from './route.documentLibrary'
import DataStatistics from './route.datastatistics'
const constantRoutes = [
// {
@@ -22,156 +20,165 @@ const constantRoutes = [
// },
{
path: '/:catchAll(.*)',
redirect: "/error/404",
meta: { noRedirectLogin: true },
redirect: '/error/404',
meta: { noRedirectLogin: true }
},
{
path: "/",
redirect: "/home"
path: '/',
redirect: '/home'
},
{
path: "/heartbeat",
component: () => import(/* webpackChunkName: 'heartbeat' */ "@views/Heartbeat/Index.vue"),
path: '/heartbeat',
component: () => import(/* webpackChunkName: 'heartbeat' */ '@views/Heartbeat/Index.vue')
},
{
path: "/home",
name: "home",
redirect: "/home/project",
component: () => import(/* webpackChunkName: 'home' */ "@views/Home/Index.vue"),
children: [...ProjectManage, ...TemplateMarket, ...Contact, ...DocumentLibrary,...DataStatistics]
path: '/home',
name: 'home',
redirect: '/home/project',
component: () => import(/* webpackChunkName: 'home' */ '@views/Home/Index.vue'),
children: [...ProjectManage, ...TemplateMarket, ...Contact, ...DocumentLibrary, ...DataStatistics]
},
{
path: "/luck",
name: "luck",
component: () => import(/* webpackChunkName: "planet" */ "../views/planetDesign/redpacket/luck.vue")
}, {
path: "/addinfor",
name: "addinfor",
component: () => import(/* webpackChunkName: "planet" */ "../views/planetDesign/redpacket/addinfor.vue")
path: '/luck',
name: 'luck',
component: () => import(/* webpackChunkName: "planet" */ '../views/planetDesign/redpacket/luck.vue')
},
{
path: "/prize",
name: "prize",
component: () => import(/* webpackChunkName: "planet" */ "../views/planetDesign/redpacket/prize.vue")
path: '/addinfor',
name: 'addinfor',
component: () => import(/* webpackChunkName: "planet" */ '../views/planetDesign/redpacket/addinfor.vue')
},
{
path: "/succeed",
name: "succeed",
component: () => import(/* webpackChunkName: "planet" */ "../views/planetDesign/redpacket/succeed.vue")
path: '/prize',
name: 'prize',
component: () => import(/* webpackChunkName: "planet" */ '../views/planetDesign/redpacket/prize.vue')
},
{
path: "/login",
name: "login",
component: () => import(/* webpackChunkName: 'login' */ "@views/Login/Login.vue")
path: '/succeed',
name: 'succeed',
component: () => import(/* webpackChunkName: "planet" */ '../views/planetDesign/redpacket/succeed.vue')
},
{
path: "/loginInvite",
name: "loginInvite",
component: () => import(/* webpackChunkName: 'login' */ "@views/TeamManage/TeamCenter/teamAdmin/login.vue")
path: '/login',
name: 'login',
component: () => import(/* webpackChunkName: 'login' */ '@views/Login/Login.vue')
},
{
path: "/answer",
name: "Answer",
path: '/loginInvite',
name: 'loginInvite',
component: () => import(/* webpackChunkName: 'login' */ '@views/TeamManage/TeamCenter/teamAdmin/login.vue')
},
{
path: '/answer',
name: 'Answer',
meta: { noRedirectLogin: true },
component: () => import(/* webpackChunkName: "answer" */ "../views/Answer/Index.vue")
component: () => import(/* webpackChunkName: "answer" */ '../views/Answer/Index.vue')
},
{
path: "/preview",
name: "Preview",
component: () => import(/* webpackChunkName: "preview" */ "../views/Answer/Preview.vue")
path: '/preview',
name: 'Preview',
component: () => import(/* webpackChunkName: "preview" */ '../views/Answer/Preview.vue')
},
{
path: "/survey",
name: "Survey",
redirect: "/survey/planet",
component: () => import(/* webpackChunkName: "survey" */ "../views/survey/index.vue"),
path: '/survey',
name: 'Survey',
redirect: '/survey/planet',
component: () => import(/* webpackChunkName: "survey" */ '../views/survey/index.vue'),
children: [
{
path: "planet",
name: "planet",
redirect: "/survey/planet/design",
component: () => import(/* webpackChunkName: "planet" */ "../views/planetDesign/Index.vue"),
path: 'planet',
name: 'planet',
redirect: '/survey/planet/design',
component: () => import(/* webpackChunkName: "planet" */ '../views/planetDesign/Index.vue'),
children: [
{
path: "design",
name: "design",
meta: { showPreview: true, showPublish: true, showDownload: true, },
component: () => import(/* webpackChunkName: "planet" */ "../views/planetDesign/Design/DesignContent.vue")
path: 'design',
name: 'design',
meta: { showPreview: true, showPublish: true, showDownload: true },
component: () => import(/* webpackChunkName: "planet" */ '../views/planetDesign/Design/DesignContent.vue')
},
{
path: "logical",
name: "logical",
meta: { showPublish: true, showDownload: true, },
component: () => import(/* webpackChunkName: "planet" */ "../views/planetDesign/Logical/Index.vue")
path: 'logical',
name: 'logical',
meta: { showPublish: true, showDownload: true },
component: () => import(/* webpackChunkName: "planet" */ '../views/planetDesign/Logical/Index.vue')
},
{
path: "test",
meta: { showPublish: true, showDownload: true, },
component: () => import(/* webpackChunkName: "planet" */ "../views/planetDesign/PlanetTest.vue")
path: 'test',
meta: { showPublish: true, showDownload: true },
component: () => import(/* webpackChunkName: "planet" */ '../views/planetDesign/PlanetTest.vue')
},
{
path: "answer-setting",
meta: { showPublish: true, showDownload: true, },
component: () => import(/* webpackChunkName: "planet" */ "../views/planetDesign/AnswerSetting.vue")
path: 'answer-setting',
meta: { showPublish: true, showDownload: true },
component: () => import(/* webpackChunkName: "planet" */ '../views/planetDesign/AnswerSetting.vue')
},
{
path: "theme",
meta: { showPublish: true, showPreview: true, showDownload: true, },
component: () => import(/* webpackChunkName: "planet" */ "../views/planetDesign/Theme/index.vue")
path: 'theme',
meta: { showPublish: true, showPreview: true, showDownload: true },
component: () => import(/* webpackChunkName: "planet" */ '../views/planetDesign/Theme/index.vue')
},
{
path: "redpacket",
meta: { showPublish: true, showPreview: true, showDownload: true, },
component: () => import(/* webpackChunkName: "planet" */ "../views/planetDesign/redpacket/index.vue")
path: 'redpacket',
meta: { showPublish: true, showPreview: true, showDownload: true },
component: () => import(/* webpackChunkName: "planet" */ '../views/planetDesign/redpacket/index.vue')
},
{
path: "addset",
meta: { showPublish: true, showPreview: true, showDownload: true, },
component: () => import(/* webpackChunkName: "planet" */ "../views/planetDesign/redpacket/addset.vue")
path: 'addset',
meta: { showPublish: true, showPreview: true, showDownload: true },
component: () => import(/* webpackChunkName: "planet" */ '../views/planetDesign/redpacket/addset.vue')
}
]
},
{
path: "schedule",
name: "schedule",
redirect: "/survey/schedule/index",
component: () => import(/* webpackChunkName: "planet" */ "../views/schedule/index.vue"),
path: 'schedule',
name: 'schedule',
redirect: '/survey/schedule/index',
component: () => import(/* webpackChunkName: "planet" */ '../views/schedule/index.vue'),
children: [
{
path: "recycle",
name: "recycle",
meta: { showPreview: true, showPublish: true, showDownload: true, },
component: () => import(/* webpackChunkName: "planet" */ "../views/schedule/recycle.vue")
},]
path: 'recycle',
name: 'recycle',
meta: { showPreview: true, showPublish: true, showDownload: true },
component: () => import(/* webpackChunkName: "planet" */ '../views/schedule/recycle.vue')
}
]
},
{
path: "analyse",
name: "analyse",
path: 'analyse',
name: 'analyse',
redirect: { name: 'Diagram' },
meta: { keepAlive: false },
component: () => import(/* webpackChunkName: "analyse" */ "@/views/DataAnalyse/index"),
component: () => import(/* webpackChunkName: "analyse" */ '@/views/DataAnalyse/index'),
children: [
{
path: "data-particulars",
name: "DataParticulars",
path: 'data-particulars',
name: 'DataParticulars',
meta: { keepAlive: true },
meta: { showPublish: false, showPreview: false, showShare: true, showDownload: true },
component: () => import(/* webpackChunkName: "analyse" */ "@/views/DataAnalyse/particulars/list")
component: () => import(/* webpackChunkName: "analyse" */ '@/views/DataAnalyse/particulars/list')
},
{
path: "diagram",
name: "Diagram",
path: 'test-particulars',
name: 'TestParticulars',
meta: { keepAlive: true },
meta: { showPublish: false, showPreview: false, showShare: true, showDownload: true },
component: () => import(/* webpackChunkName: "analyse" */ '@/views/DataAnalyse/particulars/test')
},
{
path: 'diagram',
name: 'Diagram',
meta: { keepAlive: true, showDownload: true },
component: () => import(/* webpackChunkName: "analyse" */ "@/views/DataAnalyse/diagram/test")
component: () => import(/* webpackChunkName: "analyse" */ '@/views/DataAnalyse/diagram/test')
},
{
path: "test",
name: "test",
path: 'test',
name: 'test',
meta: { keepAlive: true },
component: () => import(/* webpackChunkName: "analyse" */ "@/views/DataAnalyse/diagram/test")
component: () => import(/* webpackChunkName: "analyse" */ '@/views/DataAnalyse/diagram/test')
},
{
path: "kndiagram",
@@ -209,65 +216,64 @@ const constantRoutes = [
// path: "index",
// component: () => import(/* webpackChunkName: "analyse" */ "@/views/DataAnalyse/kndiagram/index"),
// }
},
{
path: "bi",
name: "bi",
component: () => import(/* webpackChunkName: "publish" */ "@/views/Publish/bi")
path: 'bi',
name: 'bi',
component: () => import(/* webpackChunkName: "publish" */ '@/views/Publish/bi')
},
{
// BPTO模拟
path: "bptoAnalog",
name: "bptoAnalog",
path: 'bptoAnalog',
name: 'bptoAnalog',
meta: { keepAlive: true },
component: () => import(/* webpackChunkName: "analyse" */ "@/views/DataAnalyse/bptoAnalog/index")
component: () => import(/* webpackChunkName: "analyse" */ '@/views/DataAnalyse/bptoAnalog/index')
},
{
path: "crosstabs",
name: "crosstabs",
path: 'crosstabs',
name: 'crosstabs',
meta: { keepAlive: true, showDownload: true },
component: () => import(/* webpackChunkName: "analyse" */ "@/views/DataAnalyse/crosstabs/index.vue")
component: () => import(/* webpackChunkName: "analyse" */ '@/views/DataAnalyse/crosstabs/index.vue')
},
{
path: "recycleBin",
name: "recycleBin",
component: () => import(/* webpackChunkName: "analyse" */ "@/views/DataAnalyse/recycleBin/index"),
redirect: "detailData",
children: [{
name: "数据明细",
path: "detailData",
// meta: {title:"数据明细" },
component: () => import(/* webpackChunkName: "analyse" */ "@/views/DataAnalyse/recycleBin/binList/detailData"),
}
],
},
path: 'recycleBin',
name: 'recycleBin',
component: () => import(/* webpackChunkName: "analyse" */ '@/views/DataAnalyse/recycleBin/index'),
redirect: 'detailData',
children: [
{
name: '数据明细',
path: 'detailData',
// meta: {title:"数据明细" },
component: () => import(/* webpackChunkName: "analyse" */ '@/views/DataAnalyse/recycleBin/binList/detailData')
}
]
}
]
},
{
path: "publish",
name: "publish",
redirect: "/survey/publish/link",
component: () => import(/* webpackChunkName: "publish" */ "@/views/Publish/index"),
path: 'publish',
name: 'publish',
redirect: '/survey/publish/link',
component: () => import(/* webpackChunkName: "publish" */ '@/views/Publish/index'),
children: [
{
path: "link-source",
name: "link-source",
path: 'link-source',
name: 'link-source',
meta: { showPreview: false, showPublish: false, keepAlive: true, showShare: true },
component: () => import(/* webpackChunkName: "publish" */ "@/views/Publish/link")
component: () => import(/* webpackChunkName: "publish" */ '@/views/Publish/link')
},
{
path: "link",
name: "link",
path: 'link',
name: 'link',
meta: { showPreview: false, showPublish: false, keepAlive: true, showShare: true },
component: () => import(/* webpackChunkName: "publish" */ "@/views/Publish/launch-center/launch-task/index")
component: () => import(/* webpackChunkName: "publish" */ '@/views/Publish/launch-center/launch-task/index')
},
{
path: "create",
name: "create",
path: 'create',
name: 'create',
meta: { showPreview: false, showPublish: false, keepAlive: true, showShare: true },
component: () => import(/* webpackChunkName: "publish" */ "@/views/Publish/launch-center/launch-task/create")
component: () => import(/* webpackChunkName: "publish" */ '@/views/Publish/launch-center/launch-task/create')
},
// {
// path: "link",
@@ -276,80 +282,86 @@ const constantRoutes = [
// component: () => import(/* webpackChunkName: "publish" */ "@/views/Publish/link")
// },
{
path: "analyst",
name: "analyst",
path: 'analyst',
name: 'analyst',
meta: { showPreview: false, showPublish: false, keepAlive: true, showShare: true },
component: () => import(/* webpackChunkName: "publish" */ "@/views/Publish/analyse")
component: () => import(/* webpackChunkName: "publish" */ '@/views/Publish/analyse')
},
{
path: "api",
name: "api",
component: () => import(/* webpackChunkName: "publish" */ "@/views/Publish/api")
path: 'api',
name: 'api',
component: () => import(/* webpackChunkName: "publish" */ '@/views/Publish/api')
},
{
path: "email",
name: "email",
component: () => import(/* webpackChunkName: "publish" */ "@/views/Publish/message/record"),
path: 'email',
name: 'email',
component: () => import(/* webpackChunkName: "publish" */ '@/views/Publish/message/record')
},
{
path: "census",
name: "census",
component: () => import(/* webpackChunkName: "publish" */ "@/views/Publish/census/census"),
path: 'census',
name: 'census',
component: () => import(/* webpackChunkName: "publish" */ '@/views/Publish/census/census')
},
{
path: "emailRecord",
name: "emailRecord",
component: () => import(/* webpackChunkName: "publish" */ "@/views/Publish/email/email")
path: 'emailRecord',
name: 'emailRecord',
component: () => import(/* webpackChunkName: "publish" */ '@/views/Publish/email/email')
},
{
path: "message",
name: "message",
component: () => import(/* webpackChunkName: "publish" */ "@/views/Publish/message/record")
path: 'message',
name: 'message',
component: () => import(/* webpackChunkName: "publish" */ '@/views/Publish/message/record')
},
{
path: "messageRecord",
name: "messageRecord",
component: () => import(/* webpackChunkName: "publish" */ "@/views/Publish/message/message")
path: 'messageRecord',
name: 'messageRecord',
component: () => import(/* webpackChunkName: "publish" */ '@/views/Publish/message/message')
},
{
path: "sample",
name: "sample",
component: () => import(/* webpackChunkName: "publish" */ "@/views/Publish/sample/sample")
path: 'sample',
name: 'sample',
component: () => import(/* webpackChunkName: "publish" */ '@/views/Publish/sample/sample')
},
{
path: "activity",
name: "activity",
component: () => import(/* webpackChunkName: "publish" */ "@/views/Publish/activity/activity")
path: 'activity',
name: 'activity',
component: () => import(/* webpackChunkName: "publish" */ '@/views/Publish/activity/activity')
},
{
path: "group",
name: "group",
component: () => import(/* webpackChunkName: "publish" */ "@/views/Publish/temp")
path: 'group',
name: 'group',
component: () => import(/* webpackChunkName: "publish" */ '@/views/Publish/temp')
},
{
path: "flush",
name: "flush",
component: () => import(/* webpackChunkName: "publish" */ "@/views/Publish/flush")
},
path: 'flush',
name: 'flush',
component: () => import(/* webpackChunkName: "publish" */ '@/views/Publish/flush')
}
]
},
}
]
},
{
path: "/InviteLogin",
name: "InviteLogin",
component: () => import(/* webpackChunkName: 'InviteLogin' */ "../views/TeamManage/InviteLogin.vue")
path: '/not-data',
name: 'notData',
// meta: { showPublish: false, showPreview: false, showShare: true, showDownload: true },
component: () => import(/* webpackChunkName: "analyse" */ '@/views/DataAnalyse/particulars/notData/notData')
},
{
path: "/team-manage",
name: "TeamManage",
component: () => import(/* webpackChunkName: 'home' */ "../views/TeamManage/index.vue"),
path: '/InviteLogin',
name: 'InviteLogin',
component: () => import(/* webpackChunkName: 'InviteLogin' */ '../views/TeamManage/InviteLogin.vue')
},
{
path: '/team-manage',
name: 'TeamManage',
component: () => import(/* webpackChunkName: 'home' */ '../views/TeamManage/index.vue'),
children: [
{
path: "user-center",
name: "userCenTer",
component: () => import(/* webpackChunkName: 'home' */ "../views/TeamManage//UserCenter/index.vue"),
path: 'user-center',
name: 'userCenTer',
component: () => import(/* webpackChunkName: 'home' */ '../views/TeamManage//UserCenter/index.vue')
// children: [
// {
// path: "design",
@@ -380,11 +392,11 @@ const constantRoutes = [
// ]
},
{
path: "team-center",
name: "teamCenter",
component: () => import(/* webpackChunkName: 'home' */ "../views/TeamManage//TeamCenter/index.vue")
},
],
path: 'team-center',
name: 'teamCenter',
component: () => import(/* webpackChunkName: 'home' */ '../views/TeamManage//TeamCenter/index.vue')
}
]
},
// 下载中心
// {
@@ -393,13 +405,13 @@ const constantRoutes = [
// component: () => import(/* webpackChunkName: "preview" */ "../views/DownloadCenter/index.vue")
// },
...routes
];
]
export const asyncRoutes = [];
export const asyncRoutes = []
const router = createRouter({
history: createWebHashHistory(),
routes: constantRoutes
});
})
router.beforeEach((to, from, next) => {
if (!to.meta.noRedirectLogin) {
if (window.self === window.top) {
@@ -408,4 +420,4 @@ router.beforeEach((to, from, next) => {
}
next()
})
export default router;
export default router

View File

@@ -4,71 +4,75 @@ import qs from 'qs'
const conUrl = '/console'
export default {
namespaced: true,
state:{
selectKeys:[],
dataFilterInfo:{},
exportInfo:{}
state: {
selectKeys: [],
selectIds: [],
dataFilterInfo: {},
exportInfo: {}
},
actions:{
exportInfo({state},data){
actions: {
exportInfo({ state }, data) {
state.exportInfo = data
},
// 题目答案数据清洗
cleanAnswer({state},{answer,question}){
console.log('开始数据清洗',answer);
cleanAnswer({ state }, { answer, question }) {
console.log('开始数据清洗', answer)
let newChild = []
// 判断是否有修改过的题型
let isFlag = false
for (let i = 0; i < answer.child.length; i++) {
const el = answer.child[i];
const el = answer.child[i]
let flag = true
let questionList = []
question.map(cel=>{
question.map((cel) => {
questionList.push(cel.question_index)
if(cel.question_index ===el.question_index&& cel.question_type !== el.question_type){
if (cel.question_index === el.question_index && cel.question_type !== el.question_type) {
flag = false
isFlag = true
}
})
if(questionList.length>0&&!questionList.includes(el.question_index)){
if (questionList.length > 0 && !questionList.includes(el.question_index)) {
flag = false
isFlag = true
}
if(flag){
if (flag) {
newChild.push(el)
}
}
if(newChild.length>0){
if (newChild.length > 0) {
answer.child = newChild
}else{
} else {
answer.child = [{}]
}
return {answer,isFlag}
return { answer, isFlag }
},
selectKeys({state},data){
selectKeys({ state }, data) {
state.selectKeys = data
},
dataFilterInfo({state},data){
selectIds({ state }, data) {
state.selectIds = data
},
dataFilterInfo({ state }, data) {
state.dataFilterInfo = data
},
// 投放列表
getSurveysAnswers(vuex, data = {}) {
if(data.answer&&typeof data.answer =='object'){
if (data.answer && typeof data.answer == 'object') {
data.answer = JSON.stringify(data.answer)
}
console.log('筛选列表数据',data);
console.log('筛选列表数据', data)
return request({
url: `${conUrl}/surveys/${data.sn}/answers`,
method: 'POST',
data
});
})
},
getSurveysHead(vuex, param = {}) {
return request({
url: `${conUrl}/surveys/${param.sn}/answers/heads`,
method: 'GET',
param
});
})
},
// 数据明细-导出pdf|zip
getSurveysAnswersExport(vuex, data = {}) {
@@ -76,7 +80,7 @@ export default {
url: `${conUrl}/surveys/${data.sn}/answers_export`,
method: 'POST',
data
});
})
},
// 数据明细-下载
getSurveysAnswersDown(vuex, data = {}) {
@@ -84,7 +88,7 @@ export default {
url: `${conUrl}/surveys/${data.sn}/answers_download`,
method: 'POST',
data
});
})
},
// 数据明细-回收站
delSurveysAnswers(vuex, data = {}) {
@@ -92,7 +96,7 @@ export default {
url: `${conUrl}/surveys/${data.sn}/answers`,
method: 'DELETE',
data
});
})
},
// 筛选方案列表
getTemplateExport(vuex, param = {}) {
@@ -100,16 +104,16 @@ export default {
url: `${conUrl}/surveys/${param.sn}/template_export`,
method: 'GET',
param
});
})
},
// 导入作答信息
postAnswersImport(vuex, data = {}) {
let sn = data.get("sn")
let sn = data.get('sn')
return request({
url: `${conUrl}/surveys/${sn}/answers_import`,
method: 'POST',
data
});
})
},
// 筛选方案列表
getSurveysAnswerFilter(vuex, param = {}) {
@@ -117,7 +121,7 @@ export default {
url: `${conUrl}/surveys/${param.sn}/answer_filter`,
method: 'GET',
param
});
})
},
// 筛选方案新增
postSurveysAnswers(vuex, data = {}) {
@@ -125,7 +129,7 @@ export default {
url: `${conUrl}/surveys/${data.sn}/answer_filter`,
method: 'POST',
data
});
})
},
// 筛选方案复制
postSurveysAnswersClone(vuex, data = {}) {
@@ -133,7 +137,7 @@ export default {
url: `${conUrl}/surveys/${data.sn}/answer_filter/${data.id}`,
method: 'POST',
data
});
})
},
// 筛选方案修改
putSurveysAnswers(vuex, data = {}) {
@@ -141,7 +145,7 @@ export default {
url: `${conUrl}/surveys/${data.sn}/answer_filter/${data.id}`,
method: 'PUT',
data
});
})
},
// 筛选方案置顶
putSurveysAnswersTop(vuex, data = {}) {
@@ -149,7 +153,7 @@ export default {
url: `${conUrl}/surveys/${data.sn}/answer_filter/${data.id}/top`,
method: 'PUT',
data
});
})
},
// 筛选方案删除
delSurveysAnswersTop(vuex, data = {}) {
@@ -157,7 +161,7 @@ export default {
url: `${conUrl}/surveys/${data.sn}/answer_filter/${data.id}`,
method: 'DELETE',
data
});
},
})
}
}
}
}

View File

@@ -1,22 +1,27 @@
<template>
<a-table
:row-selection="rowSelection"
:rowKey="rowKey"
:type="type"
:columns="customHeaders"
:dataSource="data"
:pagination="pagination"
:scroll="{ x: 1200 }"
@change="handlePageChange"
>
<template
v-for="col in tableHeaders"
:key="col.dataIndex"
#[col.dataIndex]="{ record, text }"
>
<template v-if="col.dataIndex !== 'operation'">
<a-table :row-selection="rowSelection" :rowKey="rowKey" :type="type" :columns="customHeaders" :dataSource="data" :pagination="pagination" :scroll="{ x: 1200 }" @change="handlePageChange">
<template v-for="col in tableHeaders" :key="col.dataIndex" #[col.dataIndex]="{ record, text }">
<template v-if="col.dataIndex === 'mark_des'">
<slot name="sign" v-bind:record="record">
{{ record.mark_des }}
</slot>
</template>
<!-- 作答类型 -->
<!-- <template v-if="col.dataIndex === 'type'">
<slot name="type" v-bind:record="record">
<span class="show-type show-type-da">作答</span>
</slot>
</template> -->
<template v-if="col.dataIndex === 'is_mark'">
<slot name="is_mark" v-bind:record="record">
<i v-if="record.is_mark" class="icon iconfont show-sign curror" @click="hideSign(record)">&#xe7d6;</i>
<i v-else class="icon iconfont hide-sign curror" @click="showSign(record)">&#xe7d6;</i>
</slot>
</template>
<template v-else-if="col.dataIndex !== 'operation'">
<render-table-title :title="text"></render-table-title>
</template>
<div v-else>
<slot name="operation" v-bind:record="record"></slot>
</div>
@@ -25,119 +30,159 @@
</template>
<script setup>
import { defineComponent, ref, toRefs, watchEffect, useAttrs,onUnmounted, reactive, useSlots,defineProps } from "vue";
import { useStore } from 'vuex';
import usePagination from "@views/DataAnalyse/composables/usePagination";
import useGeneratorTableColumns from "@views/DataAnalyse/composables/use-generator-table-columns";
import useCustomHeaderTitle from "@views/DataAnalyse/composables/useCustomHeaderTitle";
import RenderTableTitle from "@views/DataAnalyse/components/RenderTableTitle"
import { computed } from "@vue/reactivity";
import { watch } from "fs";
import * as cheerio from 'cheerio';
import { defineComponent, ref, toRefs, watchEffect, useAttrs, onUnmounted, reactive, useSlots, defineProps, createVNode, resolveComponent, h } from 'vue'
import { useStore } from 'vuex'
import usePagination from '@views/DataAnalyse/composables/usePagination'
import useGeneratorTableColumns from '@views/DataAnalyse/composables/use-generator-table-columns'
import useCustomHeaderTitle from '@views/DataAnalyse/composables/useCustomHeaderTitle'
import RenderTableTitle from '@views/DataAnalyse/components/RenderTableTitle'
import { computed } from '@vue/reactivity'
import { watch } from 'fs'
import * as cheerio from 'cheerio'
import { Input, Modal } from 'ant-design-vue'
const props = defineProps({
type: {
type: Number
},
//是否显示分页
showPagination: {
type: Boolean,
default: true
},
rowKey: {
type: [String, Number],
default: 'newSn'
},
// 每页显示数据数量
perPage: {
type: Number,
default: 10
},
// 页码
page: {
type: Number,
default: 1
},
total: {
type: Number,
default: null
},
// 表格数据
tableSource: {
type: Array,
default: () => []
},
// 表头列
tableColumns: {
type: Array,
default: () => []
},
params: {
type: Object
},
// 是否可选择
hasSelection: {
type: Boolean,
default: false
},
showOperation: {
type: Boolean,
default: true
},
sn: {
type: String,
default: ''
}
type: {
type: Number
},
//是否显示分页
showPagination: {
type: Boolean,
default: true
},
rowKey: {
type: [String, Number],
default: 'newSn'
},
// 每页显示数据数量
perPage: {
type: Number,
default: 10
},
// 页码
page: {
type: Number,
default: 1
},
total: {
type: Number,
default: null
},
// 表格数据
tableSource: {
type: Array,
default: () => []
},
// 表头列
tableColumns: {
type: Array,
default: () => []
},
params: {
type: Object
},
// 是否可选择
hasSelection: {
type: Boolean,
default: false
},
showOperation: {
type: Boolean,
default: true
},
sn: {
type: String,
default: ''
}
)
const emit = defineEmits(['change','select'])
})
const emit = defineEmits(['change', 'select'])
const store = useStore()
const data = ref([]);
const columns = ref(null);
const { perPage: per_page, total,page,rowKey } = toRefs(props);
const { pagination } = usePagination(per_page, total,page);
const { tableHeaders } = useGeneratorTableColumns(columns);
const { customHeaders } = useCustomHeaderTitle(tableHeaders, props.sn, props.params);
console.log('tableHeaders',tableHeaders);
const data = ref([])
const columns = ref(null)
const { perPage: per_page, total, page, rowKey } = toRefs(props)
const { pagination } = usePagination(per_page, total, page)
const { tableHeaders } = useGeneratorTableColumns(columns)
const { customHeaders } = useCustomHeaderTitle(tableHeaders, props.sn, props.params)
console.log('tableHeaders', tableHeaders)
// 页码&分页条数,改变时候触发
const handlePageChange =(data)=> {
const handlePageChange = (data) => {
const { pageSize, current } = data
store.dispatch('dataFilter/selectKeys',[])
store.dispatch('dataFilter/selectKeys', [])
emit('select', [])
emit('change', {
pageSize,
current
})
}
//
const selectKeys = computed(()=>store.state.dataFilter.selectKeys)
const selectList = computed(()=>store.state.dataFilter.selectKeys)
//
const selectKeys = computed(() => store.state.dataFilter.selectKeys)
const selectIds = computed(() => store.state.dataFilter.selectIds)
const selectList = computed(() => store.state.dataFilter.selectKeys)
const rowSelection = {
selectedRowKeys:selectList,
selectedRowKeys: selectList,
onChange: (selectedRowKeys, selectedRows) => {
console.log(selectedRowKeys,selectedRows);
const keys = selectedRows.map(el=>el.newSn)
store.dispatch('dataFilter/selectKeys',keys)
},
};
onUnmounted(()=>{
store.dispatch('dataFilter/selectKeys',[])
console.log(selectedRowKeys, selectedRows)
const keys = selectedRows.map((el) => el.newSn)
const ids = selectedRows.map((el) => el.id)
store.dispatch('dataFilter/selectKeys', keys)
store.dispatch('dataFilter/selectIds', ids)
}
}
onUnmounted(() => {
store.dispatch('dataFilter/selectIds', [])
store.dispatch('dataFilter/selectKeys', [])
})
watchEffect(() => {
const tableSource =JSON.parse(JSON.stringify(props.tableSource))
const tableSource = JSON.parse(JSON.stringify(props.tableSource))
// 去除标签
tableSource.map(el=>{
tableSource.map((el) => {
for (const key in el) {
const $ = cheerio.load(el[key]+'')
console.log('el[key]',el[key]);
if((el[key]+'').indexOf('<img')>-1){
const $ = cheerio.load(el[key] + '')
console.log('el[key]', el[key])
if ((el[key] + '').indexOf('<img') > -1) {
el[key] = $.html()
}else{
} else {
el[key] = $.text()
}
}
})
data.value = tableSource
columns.value = props.tableColumns;
columns.value = props.tableColumns
})
});
</script>
const showSign = (item) => {
emit('sign', [item], true)
}
const hideSign = (item) => {
emit('sign', [item], false)
}
</script>
<style lang="scss" scoped>
.show-type {
display: block;
width: auto;
padding: 0 5px;
width: 42px;
height: 22px;
line-height: 22px;
border-radius: 4px 4px 4px 4px;
opacity: 1;
font-size: 12px;
font-family: PingFang SC-常规体, PingFang SC;
font-weight: normal;
}
.show-type-da {
background: rgba(50, 176, 246, 0.2);
color: #32b0f6;
}
.show-sign {
color: #70b936;
}
.curror {
cursor: pointer;
}
.hide-sign {
cursor: pointer;
color: #bfbfbf;
}
</style>

View File

@@ -1,5 +1,5 @@
<template>
<div class='content'>
<div class="content">
<!-- <a-select
:getPopupContainer="triggerNode=>triggerNode.parentNode"
class="searchSelect operChd"
@@ -11,30 +11,30 @@
<img class="suffix-icon" :src="require('@/assets/img/select-arrow-down.png')" alt="">
</template>
</a-select> -->
<a-dropdown class="searchSelect operChd" :getPopupContainer="triggerNode=>triggerNode.parentNode">
<a-dropdown class="searchSelect operChd" :getPopupContainer="(triggerNode) => triggerNode.parentNode">
<template #overlay>
<a-menu @click="opChange">
<a-menu-item v-for="(item) in opList" :key="item.value">
{{item.label}}
<a-menu-item v-for="item in opList" :key="item.value">
{{ item.label }}
</a-menu-item>
</a-menu>
</template>
<a-button class="custom-button">
批量操作
<img class="suffix-icon" :src="require('@/assets/img/select-arrow-down.png')" alt="">
<img class="suffix-icon" :src="require('@/assets/img/select-arrow-down.png')" alt="" />
</a-button>
</a-dropdown>
<a-button class="operChd custom-button" @click="emit('cleanAllBtn',true)">清空数据</a-button>
<a-button class="operChd custom-button" @click="emit('cleanAllBtn', true)">清空数据</a-button>
<!-- <a-button class="operChd" @click="handleDownload">下载全部答卷</a-button> -->
<a-dropdown class="searchSelect operChd" :getPopupContainer="triggerNode=>triggerNode.parentNode">
<a-dropdown class="searchSelect operChd" :getPopupContainer="(triggerNode) => triggerNode.parentNode">
<template #overlay>
<a-menu @click="dataChange">
<a-menu-item v-for="(item) in dataList" :key="item.value">
{{item.label}}
<a-menu-item v-for="item in dataList" :key="item.value">
{{ item.label }}
</a-menu-item>
</a-menu>
</template>
<a-button type="primary" class="custom-button">
<a-button type="primary" class="custom-button">
数据管理
<!-- <img class="suffix-icon" :src="require('@/assets/img/select-arrow-down.png')" alt=""> -->
<CaretDownOutlined class="suffix-icon" />
@@ -50,207 +50,207 @@
<img class="suffix-icon" :src="require('@/assets/img/select-arrow-down.png')" alt="">
</template>
</a-select> -->
<a-button type="primary" class="operChd custom-button" @click="configVisible=true">列表配置</a-button>
<a-button type="primary" class="operChd custom-button" @click="router.push(`/not-data?sn=${sn}`)">无效样本处理</a-button>
<a-button type="primary" class="operChd custom-button" @click="configVisible = true">列表配置</a-button>
</div>
<!-- 配置 -->
<ColumnConfig
v-model:visible="configVisible"
:data="answer_columns"
:sn="sn"
@ok="handleConfig"
/>
<ColumnConfig v-model:visible="configVisible" :data="answer_columns" :sn="sn" @ok="handleConfig" />
<!-- 导出 -->
<DownloadData
v-model:visible="downloadVisible"
:params="queryState"
:sn="sn"
:sns="selectedSns"
@ok="handleDownload"
/>
<DownloadData v-model:visible="downloadVisible" :params="queryState" :sn="sn" :sns="selectedSns" @ok="handleDownload" />
<!-- 下载中心 -->
<DownloadCenter v-model:visible="downloadCenterVisible" v-if="downloadCenterVisible"></DownloadCenter>
</template>
<script setup>
import { ref, toRefs, reactive,defineProps,watch,onMounted , computed ,nextTick} from 'vue';
import { useRouter, useRoute } from 'vue-router';
import { useStore } from 'vuex';
import { message } from 'ant-design-vue';
import ColumnConfig from "./../../particulars/components/ColumnConfig";
import DownloadData from "./../../particulars/components/DownloadData";
import { addDownloadCenter } from "@/api/download.js";
import DownloadCenter from "@/views/DownloadCenter/index.vue"
import { CaretDownOutlined } from '@ant-design/icons-vue';
import { Modal } from 'ant-design-vue';
const props = defineProps({
answer_columns:{
type:Array,
default:()=>[]
},
selectedSns:{}
})
const store = useStore()
const {selectedSns} = toRefs(props)
const answer_columns = computed(()=>props.answer_columns)
console.log('==========answer_columns',answer_columns.value);
const emit = defineEmits()
const route = useRoute()
const router = useRouter()
const sn = computed(() => route.query.sn)
const searchData = ref({
test1:null,
test2:null
})
const opList = ref([
{value:'0',label:'下载答卷'},
{value:'1',label:'导出数据'},
{value:'2',label:'删除'}
])
// 导出选中答卷
const opChange = (e)=>{
const {key} = e
console.log(key);
if(selectKeys.value.length===0){
message.error('请选择需要操作的数据');
return
}
if(key=='0'){
getSurveysAnswersExport()
}
if(key=='1'){
// getSurveysAnswersDown()
emit('dataExport',1)
}
if(key=='2'){
// delSurveysAnswers()
emit('delFn')
}
</template>
<script setup>
import { ref, toRefs, reactive, defineProps, watch, onMounted, computed, nextTick } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { useStore } from 'vuex'
import { message } from 'ant-design-vue'
import ColumnConfig from './../../particulars/components/ColumnConfig'
import DownloadData from './../../particulars/components/DownloadData'
import { addDownloadCenter } from '@/api/download.js'
import DownloadCenter from '@/views/DownloadCenter/index.vue'
import { CaretDownOutlined } from '@ant-design/icons-vue'
import { Modal } from 'ant-design-vue'
const props = defineProps({
answer_columns: {
type: Array,
default: () => []
},
selectedSns: {}
})
const store = useStore()
const { selectedSns } = toRefs(props)
const answer_columns = computed(() => props.answer_columns)
console.log('==========answer_columns', answer_columns.value)
const emit = defineEmits()
const route = useRoute()
const router = useRouter()
const sn = computed(() => route.query.sn)
const searchData = ref({
test1: null,
test2: null
})
const opList = ref([
{ value: '3', label: '标记' },
{ value: '4', label: '取消标记' },
{ value: '0', label: '下载答卷' },
{ value: '1', label: '导出数据' },
{ value: '2', label: '删除' }
])
// 导出选中答卷
const opChange = (e) => {
const { key } = e
console.log(key)
if (selectKeys.value.length === 0) {
message.error('请选择需要操作的数据')
return
}
const dataList = ref([
// {value:'0',label:'添加数据'},
// {value:'1',label:'导入数据'},
{value:'2',label:'导出数据'},
])
// 添加数据 导入数据 导出数据
const dataChange = (e)=>{
const {key} = e
console.log(key);
if(key=='0'){
getSurveysAnswersDown()
}
if(key=='1'){
emit('dataImport')
}
if(key=='2'){
emit('dataExport',0)
}
if (key == '0') {
getSurveysAnswersExport()
}
// 配置列表
const configVisible = ref(false);
const handleConfig =()=> {
emit('configOk')
if (key == '1') {
// getSurveysAnswersDown()
emit('dataExport', 1)
}
// 导出
const downloadVisible = ref(false);
const downloadCenterVisible = ref(false)
const queryState = ref({})
const handleDownload = ()=>{
emit('downloadOk')
if (key == '2') {
// delSurveysAnswers()
emit('delFn')
}
const selectKeys = computed(()=>store.state.dataFilter.selectKeys)
// 导出
const getSurveysAnswersExport = async()=>{
try {
const subData = {
sn:sn.value,
sns:selectKeys.value.join()
if (key == '3') {
// delSurveysAnswers()
emit('sign', undefined, true)
}
if (key == '4') {
// delSurveysAnswers()
emit('sign', undefined, false)
}
}
const dataList = ref([
// {value:'0',label:'添加数据'},
{ value: '1', label: '导入数据' }
//{value:'2',label:'导出数据'},
])
// 添加数据 导入数据 导出数据
const dataChange = (e) => {
const { key } = e
console.log(key)
if (key == '0') {
getSurveysAnswersDown()
}
if (key == '1') {
emit('dataImport')
}
if (key == '2') {
emit('dataExport', 0)
}
}
// 配置列表
const configVisible = ref(false)
const handleConfig = () => {
emit('configOk')
}
// 导出
const downloadVisible = ref(false)
const downloadCenterVisible = ref(false)
const queryState = ref({})
const handleDownload = () => {
emit('downloadOk')
}
const selectKeys = computed(() => store.state.dataFilter.selectKeys)
// 导出
const getSurveysAnswersExport = async () => {
try {
const subData = {
sn: sn.value,
sns: selectKeys.value.join()
}
if (selectKeys.value.length == 1) {
const res = await store.dispatch('dataFilter/getSurveysAnswersExport', subData)
// download(res.data.download_url)
// console.log('getSurveysAnswersExport',res);
const { title, url } = res.data.download_url
const subdata = {
fileURL: url,
fileName: title
}
if(selectKeys.value.length==1) {
const res =await store.dispatch('dataFilter/getSurveysAnswersExport',subData)
// download(res.data.download_url)
// console.log('getSurveysAnswersExport',res);
const {title,url} = res.data.download_url;
const subdata = {
fileURL:url,
fileName:title
}
store.dispatch('common/fileDown',subdata)
}else{
let data ={ download_type: '2', sns:selectKeys.value.join()}
addDownloadCenter(sn.value,data).then(res=>{
// 下载中心
store.dispatch('downloadCenter/changeCenterUrl',route.path)
// downloadCenterVisible.value = true
store.dispatch('downloadCenter/changeCenterShow',true)
// router.push({
// path: "/downloadCenter",
// query: { path:route.path,sn:sn.value },
// });
})
}
} catch (error) {
console.error(error);
store.dispatch('common/fileDown', subdata)
} else {
let data = { download_type: '2', sns: selectKeys.value.join() }
addDownloadCenter(sn.value, data).then((res) => {
// 下载中心
store.dispatch('downloadCenter/changeCenterUrl', route.path)
// downloadCenterVisible.value = true
store.dispatch('downloadCenter/changeCenterShow', true)
// router.push({
// path: "/downloadCenter",
// query: { path:route.path,sn:sn.value },
// });
})
}
} catch (error) {
console.error(error)
}
// 下载
const dataFilterInfo = computed(()=>store.state.dataFilter.dataFilterInfo)
const getSurveysAnswersDown = async()=>{
try {
const subData = {
...dataFilterInfo.value,
sn:sn.value,
sns:selectKeys.value.join(),
}
const res =await store.dispatch('dataFilter/getSurveysAnswersDown',subData)
download(res.data.download_url)
console.log('getSurveysAnswersDown',res);
} catch (error) {
console.error(error);
}
// 下载
const dataFilterInfo = computed(() => store.state.dataFilter.dataFilterInfo)
const getSurveysAnswersDown = async () => {
try {
const subData = {
...dataFilterInfo.value,
sn: sn.value,
sns: selectKeys.value.join()
}
const res = await store.dispatch('dataFilter/getSurveysAnswersDown', subData)
download(res.data.download_url)
console.log('getSurveysAnswersDown', res)
} catch (error) {
console.error(error)
}
// 删除
const delSurveysAnswers = async (flag)=>{
try {
const subData = {
sn:sn.value,
}
if(!flag)subData.sns = selectKeys.value.join()
else subData.full = 1
const res =await store.dispatch('dataFilter/delSurveysAnswers',subData)
store.dispatch('dataFilter/selectKeys',[])
emit('delOk')
} catch (error) {
console.error(error);
}
// 删除
const delSurveysAnswers = async (flag) => {
try {
const subData = {
sn: sn.value
}
if (!flag) subData.sns = selectKeys.value.join()
else subData.full = 1
const res = await store.dispatch('dataFilter/delSurveysAnswers', subData)
store.dispatch('dataFilter/selectKeys', [])
emit('delOk')
} catch (error) {
console.error(error)
}
const download = (data)=>{
const url = data
const a = document.createElement("a"); // 创建a标签
a.setAttribute("download", ""); // download属性
a.setAttribute("href", url); // href链接
a.click(); // 自执行点击事件
}
defineExpose({delSurveysAnswers})
</script>
<style scoped lang='scss'>
.content{
display: flex;
align-items: center;
height: 80px;
}
.searchSelect{
width: 110px;
display: flex;
justify-content: space-between;
align-items: center;
}
.operChd:not(:first-child){
margin-left: 14px;
}
.suffix-icon{
position: relative;
z-index: 2;
width: auto;
height: 12px;
}
</style>
}
const download = (data) => {
const url = data
const a = document.createElement('a') // 创建a标签
a.setAttribute('download', '') // download属性
a.setAttribute('href', url) // href链接
a.click() // 自执行点击事件
}
defineExpose({ delSurveysAnswers })
</script>
<style scoped lang="scss">
.content {
display: flex;
align-items: center;
height: 80px;
}
.searchSelect {
width: 110px;
display: flex;
justify-content: space-between;
align-items: center;
}
.operChd:not(:first-child) {
margin-left: 14px;
}
.suffix-icon {
position: relative;
z-index: 2;
width: auto;
height: 12px;
}
</style>

View File

@@ -342,12 +342,12 @@
</a-select>
</div>
</div>
<!-- <div class="filterBox">
<div class="filterBox">
<div class="filterBoxL">是否被标记</div>
<div class="filterBoxR flexBox">
<a-switch v-model:checked="searchData.isMark" />
</div>
</div> -->
</div>
</div>
<div class="isAllOpen">
<div
@@ -1396,7 +1396,7 @@ defineExpose({
}
.filterBoxL {
// width: 80px;
width: 60px;
width: 70px;
margin-right: 20px;
flex-shrink: 0;
}

View File

@@ -4,6 +4,7 @@ const defaultOptions = {
left_fixed_key: 'id',// 左侧固定列
right_fixed_key: 'operation', //右侧固定列
show_operator: true, // 是否显示操作列
show_check:true,
}
/**
@@ -15,9 +16,42 @@ function includeSpecialType(type) {
}
export default function useGeneratorTableColumns(columns, options = {}) {
debugger;
options = {...defaultOptions, ...options}
const tableHeaders = ref([])
function flatData(columns) {
let columnsSing ={};
let columnsType ={};
let columnsMemo= {};
if(options.show_check){
columnsSing={
title: '',
key: 'is_mark',
dataIndex: 'is_mark',
align: 'center',
width: 50,
slots: {customRender: "is_mark" },
fixed: 'left',
}
columnsType={
title: '数据类型',
key: 'type',
dataIndex: 'type',
align: 'center',
width: 100,
slots: {customRender: "type" },
fixed: 'left',
}
columnsMemo={
title: '标记原因',
key: 'mark_des',
dataIndex: 'mark_des',
align: 'center',
width: 100,
slots: {customRender: "mark_des" },
fixed: 'left',
}
}
let result = columns.reduce((previousValue, currentValue) => {
const arr = Object.entries(currentValue).map(([key, value]) => ({
...value,
@@ -33,17 +67,24 @@ export default function useGeneratorTableColumns(columns, options = {}) {
// 手动修改作答ID数组位置
const snData = result.find(el=>el.key =='id')
result = result.filter(el=>el.key!='id')
// const snData = result.find(el=>el.key =='id')
// result = result.filter(el=>el.key!='id')
result.unshift(columnsMemo);
// result.unshift(columnsType);
if(snData)result.unshift(snData)
result.unshift(columnsSing);
if(options.show_operator) {
result.push({
title: '操作',
key: 'operation',
dataIndex: 'operation',
width: 130,
width: 250,
slots: {customRender: "operation" },
fixed: 'right',
})
}
return result
}
watch(columns, (data) => {

View File

@@ -1,6 +1,7 @@
import { ref, watch } from "vue";
import CustomTableHeaderCell from '@/views/DataAnalyse/components/CustomTableHeaderCell'
export default function renderCustomHeader(columns, sn ,search_params) {
const customHeaders = ref([])
function renderCell(data, sn, search_params) {

View File

@@ -77,7 +77,12 @@ export default defineComponent({
name: '明细数据',
icon: '&#xe687;',
children: [
{
// {
// name: '测试数据',
// icon: '&#xe7af;',
// path: '/survey/analyse/test-particulars'
// },
{
name: '原始数据',
icon: '&#xe7af;',
path: '/survey/analyse/data-particulars'

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,71 @@
<template>
<transfer
:data-source="mockData"
:show-search="false"
:show-select-all="false"
:list-style="{
width: '250px',
height: '300px'
}"
:target-keys="targetKeys"
:render="(item) => `${item.title}-${item.description}`"
@change="handleChange">
<!-- <template #footer>
<a-button size="small" style="float: right; margin: 5px" @click="getMock">reload</a-button>
</template> -->
<template #notFoundContent>
<span>没数据</span>
</template>
</transfer>
</template>
<script>
import { defineComponent, ref, onMounted } from 'vue'
import { Transfer } from 'ant-design-vue'
export default defineComponent({
components: {
Transfer
},
setup() {
const mockData = ref([])
const targetKeys = ref([])
onMounted(() => {
getMock()
})
const getMock = () => {
const keys = []
const mData = []
for (let i = 0; i < 20; i++) {
const data = {
key: i.toString(),
title: `content${i + 1}`,
description: `description of content${i + 1}`,
chosen: Math.random() * 2 > 1
}
if (data.chosen) {
keys.push(data.key)
}
mData.push(data)
}
mockData.value = mData
targetKeys.value = keys
}
const handleChange = (keys, direction, moveKeys) => {
targetKeys.value = keys
console.log(keys, direction, moveKeys)
}
return {
mockData,
targetKeys,
handleChange,
getMock
}
}
})
</script>

View File

@@ -0,0 +1,35 @@
<template>
<div class="hearder">
<slot>
<i class="iconfont icon-xiangzuo-moren"></i>
<span class="hearder-title">返回分析列表</span>
</slot>
</div>
</template>
<script>
export default {}
</script>
<style lang="scss" scoped>
.hearder {
width: 100%;
height: 70px;
line-height: 70px;
padding: 0 33px;
background: #ffffff;
box-shadow: 0px 2px 12px 0px rgba(0, 0, 0, 0.0614);
border-radius: 0px 0px 0px 0px;
opacity: 1;
}
.hearder-title {
margin-left: 10px;
font-size: 16px;
font-family: PingFang SC-常规体, PingFang SC;
font-weight: normal;
color: #434343;
}
.icon-xiangzuo-moren {
cursor: pointer;
}
</style>

View File

@@ -0,0 +1,32 @@
<template>
<div class="not-data-header-title">
<icon class="icon iconfont">&#xe7d4;</icon>
<div class="title">
<slot>关键词注释</slot>
</div>
</div>
</template>
<script>
export default {}
</script>
<style lang="scss" scoped>
.not-data-header-title {
margin: 24px 21px;
display: flex;
justify-items: center;
align-items: center;
.icon {
color: #90cf5e;
font-size: 16px;
}
.title {
font-size: 14px;
font-family: PingFang SC-常规体, PingFang SC;
font-weight: normal;
color: rgba(0, 0, 0, 0.85);
margin-left: 8px;
}
}
</style>

View File

@@ -0,0 +1,59 @@
<template>
<div>
<div class="function-memo">
<div class="function-memo-title">
<slot name="title"> 方法说明</slot>
</div>
<slot name="icon">
<div class="function-memo-icon">
<i class="icon iconfont" @click="hide" v-if="!isShow">&#xe76a;</i>
<i class="icon iconfont" @click="show" v-else>&#xe76b;</i>
</div>
</slot>
</div>
</div>
</template>
<script>
export default {
props: {
isShow: {
type: Boolean,
default: () => false
}
},
setup(props, context) {
const show = () => {
context.emit('update:isShow', true)
}
const hide = () => {
context.emit('update:isShow', false)
}
return {
show,
hide
}
}
}
</script>
<style lang="scss" scoped>
.function-memo {
display: flex;
font-size: 16px;
font-family: PingFang SC-中黑体, PingFang SC;
font-weight: normal;
color: rgba(0, 0, 0, 0.85);
border-bottom: 1px solid #e8e8e8;
padding: 18px 0;
margin: 0 18px;
.function-memo-icon {
flex: 1;
text-align: right;
color: #bfbfbf;
}
.function-memo-icon {
cursor: pointer;
}
}
</style>

View File

@@ -0,0 +1,225 @@
<template>
<div class="not-data">
<hearder></hearder>
<div class="not-data-title">无效样本处理</div>
<div class="flex">
<!-- -->
<div class="flex1 bgf">
<notDataHearder :style="isShow ? '100px' : '100%'" v-model:isShow="isShow"></notDataHearder>
<notDataHeaderTitle></notDataHeaderTitle>
<div class="function-content">无效样本此处指相同数字出现比例较高或缺失比例较高的样本</div>
<div class="function-content">无效样本处理指通过设置的无效样本判断规则来筛选样本并做标记或删除处理是对行的操作</div>
<notDataHeaderTitle>
<div>规则说明</div>
</notDataHeaderTitle>
<div class="function-content">前置操作作为选中变量1-4复制到检验变量列表比例设置50%以此为比例分别对相同数字缺失比例两种规则进行说明如下</div>
<div class="function-content">相同数字</div>
<div class="function-table">
<div class="function-content">以4个变量举例在变量1-4范围内相同内容出50% 及以上筛选出样本1和样本2</div>
<a-table :pagination="false" class="function-content" size="middle" :columns="test_columns" :data-source="test_data" :rowClassName="(record, index) => (index % 2 === 1 ? 'table-striped' : null)" />
</div>
<div class="function-content">缺失比例</div>
<div class="function-table">
<div class="function-content">以4个变量举例在变量1-4范围内相同内容出50% 及以上筛选出样本1和样本2</div>
<a-table :pagination="false" class="function-content" size="middle" :columns="test_columns" :data-source="test_data_2" :rowClassName="(record, index) => (index % 2 === 1 ? 'table-striped' : null)" />
</div>
</div>
<!-- -->
<div class="flex2 bgf">
<div>选择变量</div>
<div>检验变量列表变量书2</div>
<Transfer></Transfer>
</div>
<!-- -->
<div class="flex1">
<div class="bgf h50">
<notDataHearder>
<template #title> 判断标准 </template>
<template #icon>&nbsp;</template>
</notDataHearder>
<div>
<a-checkbox-group v-model:value="value">
<a-row>
<a-col :span="100">
<div class="rows-check">
<a-checkbox value="A"></a-checkbox>
删除样本 <a-input-number :min="1" :max="100000" v-model:value="value2" />&nbsp;%
</div>
</a-col>
</a-row>
<a-row>
<a-col :span="100">
<div class="rows-check">
<a-checkbox value="B"></a-checkbox>
缺失比例 <a-input-number :min="1" :max="100000" v-model:value="value2" />&nbsp;%
</div>
</a-col>
</a-row>
</a-checkbox-group>
</div>
</div>
<div class="bgf h50">
<notDataHearder>
<template #title> 处理方式 </template>
<template #icon>&nbsp;</template>
</notDataHearder>
<div class="rows-check">
<a-radio-group v-model:value="value">
<a-radio :style="radioStyle" :value="1">标记样本</a-radio>
<a-radio :style="radioStyle" :value="2">删除样本</a-radio>
</a-radio-group>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { ref } from '@vue/reactivity'
import hearder from './components/hearder'
import notDataHearder from './components/notDataHearder'
import notDataHeaderTitle from './components/notDataHeaderTitle'
import Transfer from './components/Transfer'
export default {
components: {
hearder,
notDataHearder,
notDataHeaderTitle,
Transfer
},
setup() {
const isShow = ref(true)
const test_columns = [
{ title: '', dataIndex: 'ben' },
{ title: '变量1', dataIndex: 'num1' },
{ title: '变量2', dataIndex: 'num2' },
{ title: '变量3', dataIndex: 'num3' },
{ title: '变量4', dataIndex: 'num4' }
]
const test_data = [
{
ben: '样本1',
num1: 2,
num2: 3,
num3: 3,
num4: 1
},
{
ben: '样本2',
num1: 'Q2A1',
num2: 'Q2A1',
num3: 'Q2A1',
num4: 2
},
{
ben: '样本3',
num1: 1,
num2: 2,
num3: 3,
num4: 5
}
]
const test_data_2 = [
{
ben: '样本1',
num1: '',
num2: '',
num3: '',
num4: '1'
},
{
ben: '样本2',
num1: '3',
num2: '2',
num3: '3',
num4: ''
},
{
ben: '样本3',
num1: '',
num2: '',
num3: '',
num4: ''
}
]
return {
isShow,
test_columns,
test_data,
test_data_2
}
}
}
</script>
<style lang="scss" scoped>
.not-data {
width: 100%;
height: 100%;
background: #f6f6f6;
opacity: 1;
.not-data-title {
height: 24px;
font-size: 16px;
font-family: PingFang SC-中黑体, PingFang SC;
font-weight: normal;
color: rgba(0, 0, 0, 0.851);
line-height: 24px;
margin: 22px 32px;
padding: 0 8px;
border-left: 4px solid #70b936;
}
.flex {
display: flex;
margin: 0 32px;
height: calc(100% - 122px - 32px);
.flex1 {
flex: 1;
margin: 0 10px;
}
.flex2 {
flex: 2;
margin: 0 10px;
}
}
}
.bgf {
background: #ffffff;
}
.h50 {
height: calc(50% - 5px);
margin: 0 0 10px 0;
}
.rows-check {
margin: 25px 32px 0 32px;
min-width: 200px;
}
.function-content {
margin: 14px 48px;
font-size: 14px;
font-family: PingFang SC-常规体, PingFang SC;
font-weight: normal;
color: #646464;
}
.function-table {
min-width: 320px;
min-height: 202px;
border-radius: 6px 6px 6px 6px;
opacity: 1;
border: 1px #d7d7d7 dashed;
margin: 0 48px;
.function-content {
margin: 12px;
font-size: 12px;
font-family: PingFang SC-常规体, PingFang SC;
font-weight: normal;
color: #646464;
}
}
</style>

View File

@@ -0,0 +1,632 @@
<template>
<a-spin tip="Loading..." :spinning="spinningFlag">
<div class="partContent">
<div class="overview" v-if="false">
<sub-title>回收进度</sub-title>
<div class="card-wrap">
<overview-card
:count="today_answer_count"
:icon="require('@/assets/img/newly_increase_icon.png')"
color="#FFA643"
title="今日回收量"
/>
<overview-card
:count="answer_count"
:icon="require('@/assets/img/data_count_icon.png')"
color="#4E7DFE"
title="完成回收总量"
/>
<overview-card
v-if="publish_number>0"
:count="publish_number"
:icon="require('@/assets/img/countNum.png')"
color="#2CD076"
title="发布数量"
/>
</div>
</div>
<div class="particulars">
<sub-title>明细数据</sub-title>
<!-- <search @onSearch="onSearch" @onReset="onSearch" v-if="true">
<div v-show="isFilted" class="filter-count">
已筛选{{ tableData.length }}条数据
</div>
</search> -->
<!-- 新的筛选 -->
<newSearch
ref="newSearchRef"
@onSearch="onSearch"
@openModal="openModal"
@searchPlan="searchPlan"
@saveVisOpen="saveVisOpen"
:versions="versions"
:logics="logics"
:questions="questions"
:count="dataCount"
:publish_types="publish_types"
:filterData="filterData"
:isArt="isArt"
:nowPlanVal="nowPlanVal"
/>
<!-- 新的操作按钮 -->
<newBtnList
ref="newBtnListRef"
v-if="total>0"
@configOk="handleConfig"
@downloadOk="handleDownload"
@delOk="getData"
@delFn="showDelMod"
@cleanAllBtn="cleanAllBtn"
@dataImport="dataImport"
@dataExport="dataExport"
:answer_columns="answer_columns"
:selectedSns="selectedSns"
/>
<!-- <newDataTable /> -->
<div class="table-container" v-if="true">
<DataTable
:has-selection="false"
:params="searchParams"
:per-page="per_page"
:page="page"
:sn="sn"
:table-columns="columns"
:table-source="tableData"
:total="total"
@change="onPageChange"
@select="onSelectChange"
>
<template #operation="{record}">
<div>
<a @click="openDetailModal(record)">查看</a>
<a style="margin: 10px;" @click="openDetailModal(record)">编辑</a>
<a-dropdown :trigger="['click']">
<a class="ant-dropdown-link" @click.prevent>
更多
<DownOutlined />
</a>
<template #overlay>
<a-menu>
<!-- <a-menu-item @click="signAvail">标记为无效</a-menu-item> -->
<a-menu-item @click="exportSingleAnswer(record)">下载答卷</a-menu-item>
<a-menu-item @click="exportData(record)">导出数据</a-menu-item>
<a-menu-item @click="showDelModal(record)">
<!-- <a-popconfirm
title="确定删除此条记录?"
ok-text="确认"
cancel-text="取消"
@confirm="delSingleAnswer(record)"
> -->
<span>删除</span>
<!-- </a-popconfirm> -->
</a-menu-item
>
</a-menu>
</template>
</a-dropdown>
</div>
</template>
</DataTable>
</div>
</div>
<sign-invalid-modal
v-model:visible="invalidVisible"
@ok="handleSignInvalid"
></sign-invalid-modal>
<download-data
v-model:visible="downloadVisible"
:params="queryState"
:sn="sn"
:sns="selectedSns"
@ok="handleDownload"
></download-data>
<!-- <column-config
v-model:visible="configVisible"
:data="answer_columns"
:sn="sn"
@ok="handleConfig"
></column-config> -->
<qs-detail
v-model:visible="detailVisible"
:data="tableData"
:detailId="detailId"
:sn="sn"
:type="0"
></qs-detail>
</div>
</a-spin>
<newModal
ref="newModalRef"
:isFilterInfo="isFilterInfo"
:operType ="operType"
:filterNewData ="filterNewData"
@modalOk="modalOk"
@isUse="isUseFun"
@isSave="isSaveFun"
@resetPlan="resetPlan"
@getNewData="getData"
@resShowFlag="resShowFlag"
/>
<!-- 下载中心 -->
<DownloadCenter v-model:visible="downloadCenterVisible" v-if="downloadCenterVisible"></DownloadCenter>
</template>
<script setup>
import { computed, onMounted, ref , reactive , watch} from "vue";
import { useStore } from 'vuex';
import { useRoute } from "vue-router";
import { message } from "ant-design-vue";
import SubTitle from "../components/SubTitle";
import OverviewCard from "./components/OverviewCard";
import SignInvalidModal from "./components/SignInvalidModal";
import DownloadData from "./components/DownloadData";
import QsDetail from "./components/QuestionnaireDetail";
import ColumnConfig from "./components/ColumnConfig";
import countIcon from "@/assets/img/data_count_icon.png";
import increaseIcon from "@/assets/img/newly_increase_icon.png";
import { answers_export, getParticularList, delParticularItem } from "@/api/data-analyse";
import { convertQueryToString } from "@utils/httpFormat";
import DataTable from "@views/DataAnalyse/components/DataTable";
import newDataTable from "@views/DataAnalyse/components/newDataTable";
import { downloadFile } from "@views/DataAnalyse/composables/downloadFile";
import search from '@/views/DataAnalyse/components/diagram/search'
import { DownOutlined } from '@ant-design/icons-vue';
import newSearch from '@/views/DataAnalyse/components/diagram/newSearch'
import newBtnList from '@/views/DataAnalyse/components/diagram/newBtnList'
import newModal from '@/views/DataAnalyse/components/diagram/newModal'
import { addDownloadCenter } from "@/api/download.js";
import DownloadCenter from "@/views/DownloadCenter/index.vue"
import { Modal } from 'ant-design-vue';
const store = useStore()
const route = useRoute();
// const sn = "ZY1Nodxr"
const sn = route.query.sn;
const tableData = ref([]);
const columns = ref(null);
const page = ref(1);
const per_page = ref(10);
const total = ref(0);
const queryState = ref({})
const searchParams = computed(() => {
return {
...queryState.value,
page: page.value,
per_page: per_page.value
};
});
// 弹窗操作
const newModalRef = ref(null)
const newBtnListRef = ref(null)
const fullFlag = ref(false)
const cleanAllBtn = (e)=>{
newModalRef.value.confirmDel('confirmDelAll')
fullFlag.value = e
}
const showDelMod = ()=>{
newModalRef.value.confirmDel('confirmDel')
fullFlag.value = false
}
const modalOk = (e)=>{
console.log('modalOk',e);
if(e==='confirmDel'){
newBtnListRef.value.delSurveysAnswers(fullFlag.value)
}
if(e==='confirmDelAll'){
newBtnListRef.value.delSurveysAnswers(fullFlag.value)
}
}
const dataImport = ()=>{
newModalRef.value.dataImportVis = true
}
const operType = ref(0)
const dataExport = (e)=>{
operType.value = e
newModalRef.value.dataExportVis = true
}
// 打开方案管理
const openModal = ()=>{
newModalRef.value.modalVis = true
}
// 保存为新方案
const filterNewData = ref(null)
const answer_count = ref("");
const publish_number = ref("");
const today_answer_count = ref("");
const invalidVisible = ref(false);
const downloadVisible = ref(false);
const configVisible = ref(false);
const detailVisible = ref(false);
const detailId = ref("");
const selectedRowKeys = ref([]);
const selectedSns = computed(() => {
return selectedRowKeys.value?.length
? tableData.value
.filter((item, index) => selectedRowKeys.value.includes(index))
.map((i) => i.sn) || []
: [];
});
const answer_columns = ref([]);
const isFilted = ref(false);
// function onSearch(payload) {
// isFilted.value = true
// queryState.value = payload
// getData()
// }
/**
* 获取列表数据
*/
// function getData(per_page = 10, page = 1) {
// const params = convertQueryToString(searchParams.value);
// getParticularList(sn, params).then((res) => {
// columns.value = res.columns;
// tableData.value = res.data
// answer_count.value = res.answer_count;
// today_answer_count.value = res.today_answer_count;
// total.value = res.meta.total;
// answer_columns.value = res.answer_columns;
// });
// }
// 修改方案信息
const filterData = ref({})
const isArt = ref(false)
const searchPlan = (e,isType)=>{
console.log('修改方案信息',e);
if(isType&&isType=='isSaveFun'){
if(newSearchRef.value.filterPlan.filterListVal ==e.id){
filterData.value=e
}
}else{
filterData.value=e
}
isArt.value = false
if(e){
isArt.value = true
}
}
// 控制显示筛选数目
const resShowFlag =async (flag)=>{
// newSearchRef.value.resShowFlag = flag
// await newSearchRef.value.getSurveysAnswerFilter()
// await newSearchRef.value.changePlan()
}
// 根据方案筛选信息
const nowPlanVal = ref(-1)
const newSearchRef = ref(null)
const isUseFun = async(e)=>{
onSearch(e)
searchPlan(e,'isUseFun')
console.log('当前使用条件',e);
if(e.id){
await newSearchRef.value.getSurveysAnswerFilter()
nowPlanVal.value = e.id
}
}
const isSaveFun = async(e)=>{
searchPlan(e,'isSaveFun')
if(e.id){
await newSearchRef.value.getSurveysAnswerFilter()
// nowPlanVal.value = e.id
}
}
const resetPlan = async(e)=>{
await newSearchRef.value.getSurveysAnswerFilter()
if(!e){
await newSearchRef.value.clearInfo()
nowPlanVal.value = '-1'
}
}
// 列表头部信息
const versions = ref([])
const questions = ref([])
const dataCount = ref(0)
const logics = ref([])
const publish_types = ref([])
const getSurveysHead = async()=>{
try {
questions.value = []
dataCount.value = 0
versions.value = []
const res = await store.dispatch('dataFilter/getSurveysHead',{sn})
console.log(res);
// 版本
versions.value = res.filters.versions;
// 发布方式
publish_types.value = res.filters.publish_types;
// 配额
logics.value = res.filters.logics;
// 完成
answer_count.value = res.answer_count;
// 发布数量
publish_number.value = res.publish_number;
// 今日
today_answer_count.value = res.today_answer_count;
// 配置
answer_columns.value = res.answer_columns;
console.log('answer_columns',answer_columns.value);
columns.value = res.columns;
// 筛选条件
questions.value= res?.filters?.answer_questions
console.log('传',questions.value);
} catch (error) {
console.error(error);
}
}
// 长度超出提示
watch(()=>answer_columns.value, nval=>{
if(nval.length>3){
Modal.confirm({
title: () => '注意',
content: () => '为保证您使用流畅列表仅展示前100列问题您可通过列表配置查看其他数据',
class: "custom-modal custom-modal-title-confirm-notice noCancel",
okText:()=>'知道了',
cancelText:()=>'',
onOk() {
console.log('onOk');
},
// onCancel() {
// console.log('onCancel');
// },
});
}
})
let subInfo = ref({})
const isFilterInfo= ref({})
function onSearch(params) {
subInfo.value =page.value
subInfo.value =per_page.value
isFilterInfo.value = {...params}
subInfo.value = {...params}
getData()
}
// 新查询
const spinningFlag = ref(true)
async function getData(pageInfo={}) {
try {
let subData = {
sn,
per_page:per_page.value,
page:page.value,
}
console.log('subInfo',subInfo.value);
subData = {...subData,...subInfo.value,...pageInfo}
if(subData.filter_type)spinningFlag.value = true
const res = await store.dispatch('dataFilter/getSurveysAnswers',subData)
if(subData.filter_type)spinningFlag.value = false
// 原配置
const newData =JSON.parse(JSON.stringify(res.data))
newData.map(el=>{
el.newSn = el.sn
el.key = el.sn
if(el.is_import===1){
delete el.sn
}
})
tableData.value = newData
total.value = res.meta.total;
page.value = res.meta.current_page;
dataCount.value= res?.meta?.total
} catch (error) {
console.error(error);
}
}
function onSelectChange(selectedList) {
selectedRowKeys.value = selectedList;
}
function signAvail() {
invalidVisible.value = true;
}
/*
* 标记无效问卷
* */
function handleSignInvalid() {
}
/**
* 导出问卷
*/
function exportAnswer() {
if (selectedSns.value.length === 0) {
message.warn("未勾选答卷,请勾选后重试");
return;
}
answers_export(sn, {
sns: selectedSns.value.join(",")
}).then((res) => {
const url = res.data.download_url;
downloadFile(url);
});
}
// 删除某条问卷
function delSingleAnswer(record) {
// delParticularItem(sn, record.sn).then(() => {
// getData()
// })
delSurveysAnswers(record.sn)
}
// 删除
const delSurveysAnswers = async (sns)=>{
try {
const subData = {
sn,
sns
}
const res =await store.dispatch('dataFilter/delSurveysAnswers',subData)
getData()
} catch (error) {
console.error(error);
}
}
function exportSingleAnswer(data) {
answers_export(sn, {
sns: data.newSn
}).then((res) => {
// const url = res.data.download_url;
// downloadFile(url);
const {title,url} = res.data.download_url;
const subdata = {
fileURL:url,
fileName:title
}
store.dispatch('common/fileDown',subdata)
});
}
function openDownloadModal() {
// if (!selectedRowKeys.value.length) {
// message.warning("未勾选答卷, 请勾选后重试");
// return;
// }
downloadVisible.value = true;
}
// 导出数据
const exportData = async ({newSn})=>{
operType.value = 1
newModalRef.value.dataExportVis = true
await store.dispatch('dataFilter/exportInfo',{flag:true,newSn})
}
const downloadCenterVisible = ref(false)
// 下载
function handleDownload() {
let data ={ download_type: '2' }
addDownloadCenter(sn,data).then(res=>{
// 下载中心
store.dispatch('downloadCenter/changeCenterUrl',route.path)
// downloadCenterVisible.value = true
store.dispatch('downloadCenter/changeCenterShow',true)
// router.push({
// path: "/downloadCenter",
// query: { path:route.path,sn },
// });
})
}
// 删除数据
const showDelModal = (record)=>{
Modal.confirm({
title: () => '确定删除?',
content: () => '您可在【回收站】查看或恢复删除的数据。',
class: "custom-modal custom-modal-title-confirm-notice",
okText:()=>'确 定',
onOk() {
delSingleAnswer(record)
},
onCancel() {
console.log('onCancel');
},
});
}
// 打开配置列modal
function openConfigModal() {
configVisible.value = true;
}
function handleConfig() {
getData();
getSurveysHead()
}
// 打开详情Modal
function openDetailModal(item) {
detailId.value = item.newSn;
detailVisible.value = true;
}
function onPageChange(data) {
console.log(data);
page.value = data.current;
per_page.value = data.pageSize;
getData({page:page.value , per_page:per_page.value});
}
// loading
onMounted(async () => {
getData();
await getSurveysHead();
// 关闭loading
spinningFlag.value = false
});
</script>
<style lang="scss" scoped>
.overview {
padding: 24px 32px 32px 32px;
background: #fff;
border-radius: 6px;
.card-wrap {
margin-top: 24px;
display: flex;
justify-content: space-between;
}
}
.particulars {
// margin-top: 24px;
padding: 24px 32px 32px 32px;
background: #fff;
border-radius: 6px;
.filter-count {
margin-top: 32px;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
color: #2f2f2f;
}
}
.setting {
height: 80px;
display: flex;
align-items: center;
.selected-data {
width: 70%;
color: #1c6fff;
font-size: 14px;
}
.advance-operation {
width: 30%;
display: flex;
justify-content: flex-end;
}
.multiple-btn {
width: 190px;
display: flex;
justify-content: space-between;
align-items: center;
img {
width: 12px;
height: 12px;
}
}
.export-btn {
margin-left: 12px;
}
}
.partContent{
min-width: 700px;
overflow-x: auto;
box-shadow: 0px 0px 6px 0px rgba(0,0,0,0.1);
}
</style>

View File

@@ -123,7 +123,7 @@ export function setSurveyStatus(params) {
export function getTagsList(params) {
return request({
method: "GET",
url: '/console/survey_tags',
url: `/console/survey_tags`,
params,
});
}

View File

@@ -30,7 +30,35 @@
:key="item.id"
>
<div style="display: flex; justify-content: space-between">
<span :style="countColor(item.color)" :title="item.title">{{ item.title }}</span>
<span :style="countColor(item.color)" :title="item.title">{{
item.title
}}</span>
</div>
</a-select-option>
<!-- <a-select-option v-for="item in tagsList" :key="item.id">
{{ item.title }}
</a-select-option> -->
</a-select>
</a-form-item>
<a-form-item label="模板标签">
<a-select
mode="multiple"
v-model:value="ruleForm.templateTags"
placeholder="选择问卷标签"
:filter-option="false"
:not-found-content="fetching ? undefined : null"
@search="fetchUser"
>
<a-select-option
:value="item.id"
:label="item.title"
v-for="item in templateTagsList"
:key="item.id"
>
<div style="display: flex; justify-content: space-between">
<span :style="countColor(item.color)" :title="item.title">{{
item.title
}}</span>
</div>
</a-select-option>
<!-- <a-select-option v-for="item in tagsList" :key="item.id">
@@ -57,27 +85,38 @@
</a-select>
</a-form-item>
<a-form-item label="创建时间">
<a-range-picker v-model:value="ruleForm.created_at" @change="handleCreated"/>
<a-range-picker
v-model:value="ruleForm.created_at"
@change="handleCreated"
/>
</a-form-item>
<a-form-item label="编辑时间">
<a-range-picker v-model:value="ruleForm.updated_at" @change="handleUpdated"/>
<a-range-picker
v-model:value="ruleForm.updated_at"
@change="handleUpdated"
/>
</a-form-item>
<a-form-item class="button" style="text-align: right">
<a-button style="margin-right:12px" type="cancel" @click="$emit('cancel')">取消</a-button>
<a-button
style="margin-right: 12px"
type="cancel"
@click="$emit('cancel')"
>取消</a-button
>
<a-button type="primary" @click="onSubmit">确定</a-button>
</a-form-item>
</a-form>
</template>
<script>
import { defineComponent, reactive, ref, onBeforeMount } from 'vue';
import { debounce } from 'lodash-es';
import { getUserList, getTagsList } from '../api';
import { defineComponent, reactive, ref, onBeforeMount } from "vue";
import { debounce } from "lodash-es";
import { getUserList, getTagsList } from "../api";
const statusOptions = [
{ label: '编辑中', value: 0 },
{ label: '发布中', value: 1 },
{ label: '已结束', value: 2 },
]
{ label: "编辑中", value: 0 },
{ label: "发布中", value: 1 },
{ label: "已结束", value: 2 },
];
export default defineComponent({
props: {
info: {
@@ -90,23 +129,25 @@ export default defineComponent({
const ruleForm = reactive({
status: [0],
owner_id: undefined,
created_at: '',
updated_at: '',
created_at: "",
updated_at: "",
tags: [],
templateTags: [],
});
let lastFetchId = 0;
const fetching = ref(false);
const userList = ref([])
const tagsList = ref([])
const userList = ref([]);
const tagsList = ref([]);
const templateTagsList = ref([]);
const handleCreated = (value, dateString) => {
console.log('dateString', dateString)
console.log("dateString", dateString);
ruleForm.created_at = dateString;
};
const handleUpdated = (value, dateString) => {
ruleForm.updated_at = dateString;
};
/** 搜索用户防抖 */
const fetchUser = debounce(value => {
const fetchUser = debounce((value) => {
lastFetchId += 1;
userList.value = [];
fetching.value = true;
@@ -114,148 +155,178 @@ export default defineComponent({
getUsers(value);
}, 500);
/** 获取用户列表 */
const getUsers = async (val)=> {
const getUsers = async (val) => {
try {
const { data } = await getUserList({nickname: val || ''});
const { data } = await getUserList({ nickname: val || "" });
const fetchId = lastFetchId;
if (fetchId !== lastFetchId) {
return;
return;
}
userList.value = data;
} catch(error) {
} catch (error) {
context.message.error(
error.data?.message || error.message || "服务器错误"
);
}
}
};
/** 获取项目标签列表 */
const getTagList = async (val)=> {
const getTagList = async () => {
try {
const { data } = await getTagsList();
console.log(data);
const fetchId = lastFetchId;
const fetchId = lastFetchId;
if (fetchId !== lastFetchId) {
return;
return;
}
tagsList.value = data;
} catch(error) {
} catch (error) {
context.message.error(
error.data?.message || error.message || "服务器错误"
);
}
}
};
/** 获取项目标签列表 */
const getTemplateTagList = async () => {
try {
const { data } = await getTagsList({
type: 2
});
console.log(data);
const fetchId = lastFetchId;
if (fetchId !== lastFetchId) {
return;
}
templateTagsList.value = data;
} catch (error) {
context.message.error(
error.data?.message || error.message || "服务器错误"
);
}
};
// 标签颜色
const countColor = (value) => {
let style = {}
let style = {};
switch (value) {
case 1:
style = {
'color' : '#4DB8FA',
'border' : '1px solid #4DB8FA',
'padding': '0 5px',
'border-radius': '4px',
'line-height': '20px',
}
break;
case 2:
style = {
'color' : '#0CC126',
// 'border-color' : '#0CC126',
'border' : '1px solid #0CC126',
'padding': '0 5px',
'border-radius': '4px',
'line-height': '20px',
}
break;
case 3:
style = {
'color' : '#FF8800',
// 'border-color' : '#FF8800',
'border' : '1px solid #FF8800',
'padding': '0 5px',
'border-radius': '4px',
'line-height': '20px',
}
break;
case 4:
style = {
'color' : '#FF374F',
// 'border-color' : '#FF374F',
'border' : '1px solid #FF374F',
'padding': '0 5px',
'border-radius': '4px',
'line-height': '20px',
}
break;
case 5:
style = {
'color' : '#1C6FFF',
// 'border-color' : '#1C6FFF',
'border' : '1px solid #1C6FFF',
'padding': '0 5px',
'border-radius': '4px',
'line-height': '20px',
}
break;
case 6:
style = {
'color' : '#11AEA7',
// 'border-color' : '#11AEA7',
'border' : '1px solid #11AEA7',
'padding': '0 5px',
'border-radius': '4px',
'line-height': '20px',
}
break;
case 7:
style = {
'color' : '#25D8C8',
// 'border-color' : '#25D8C8',
'border' : '1px solid #25D8C8',
'padding': '0 5px',
'border-radius': '4px',
'line-height': '20px',
}
break;
case 8:
style = {
'color' : '#FECB0D',
// 'border-color' : '#FECB0D',
'border' : '1px solid #FECB0D',
'padding': '0 5px',
'border-radius': '4px',
'line-height': '20px',
}
// break;
// case 9:
// style = {
// 'color' : '4DB8FA',
// 'border-color' : '4DB8FA',
// }
}
return style
}
case 1:
style = {
color: "#4DB8FA",
border: "1px solid #4DB8FA",
padding: "0 5px",
"border-radius": "4px",
"line-height": "20px",
};
break;
case 2:
style = {
color: "#0CC126",
// 'border-color' : '#0CC126',
border: "1px solid #0CC126",
padding: "0 5px",
"border-radius": "4px",
"line-height": "20px",
};
break;
case 3:
style = {
color: "#FF8800",
// 'border-color' : '#FF8800',
border: "1px solid #FF8800",
padding: "0 5px",
"border-radius": "4px",
"line-height": "20px",
};
break;
case 4:
style = {
color: "#FF374F",
// 'border-color' : '#FF374F',
border: "1px solid #FF374F",
padding: "0 5px",
"border-radius": "4px",
"line-height": "20px",
};
break;
case 5:
style = {
color: "#1C6FFF",
// 'border-color' : '#1C6FFF',
border: "1px solid #1C6FFF",
padding: "0 5px",
"border-radius": "4px",
"line-height": "20px",
};
break;
case 6:
style = {
color: "#11AEA7",
// 'border-color' : '#11AEA7',
border: "1px solid #11AEA7",
padding: "0 5px",
"border-radius": "4px",
"line-height": "20px",
};
break;
case 7:
style = {
color: "#25D8C8",
// 'border-color' : '#25D8C8',
border: "1px solid #25D8C8",
padding: "0 5px",
"border-radius": "4px",
"line-height": "20px",
};
break;
case 8:
style = {
color: "#FECB0D",
// 'border-color' : '#FECB0D',
border: "1px solid #FECB0D",
padding: "0 5px",
"border-radius": "4px",
"line-height": "20px",
};
// break;
// case 9:
// style = {
// 'color' : '4DB8FA',
// 'border-color' : '4DB8FA',
// }
}
return style;
};
/** 提交筛选条件 */
const onSubmit = () => {
formRef.value.validate().then(() => {
formRef.value
.validate()
.then(() => {
const params = {
owner_id: ruleForm.owner_id ? (ruleForm.owner_id.map(e=> e.key)).join(',') : '',
status: ruleForm.status ? ruleForm.status.join(',') : '',
created_at: ruleForm.created_at ? ruleForm.created_at.join(',') : '',
updated_at: ruleForm.updated_at ? ruleForm.updated_at.join(',') : '',
tags: ruleForm.tags ? ruleForm.tags.join(',') : '',
}
console.log('values', params);
context.emit('update', params)
owner_id: ruleForm.owner_id
? ruleForm.owner_id.map((e) => e.key).join(",")
: "",
status: ruleForm.status ? ruleForm.status.join(",") : "",
created_at: ruleForm.created_at
? ruleForm.created_at.join(",")
: "",
updated_at: ruleForm.updated_at
? ruleForm.updated_at.join(",")
: "",
tags: ruleForm.tags ? ruleForm.tags.join(",") : "",
templates_tags: ruleForm.templateTags
? ruleForm.templateTags.join(",")
: "",
};
console.log("values", params);
context.emit("update", params);
})
.catch((error) => {
console.log('error', error);
console.log("error", error);
});
};
onBeforeMount(()=> {
onBeforeMount(() => {
getUsers();
getTagList();
})
getTemplateTagList();
});
return {
formRef,
ruleForm,
@@ -264,13 +335,14 @@ export default defineComponent({
handleCreated,
handleUpdated,
statusOptions,
labelCol: { style: { width: '150px' } },
labelCol: { style: { width: "150px" } },
wrapperCol: { span: 14 },
userList,
fetching,
tagsList,
templateTagsList,
countColor,
}
};
},
})
});
</script>

View File

@@ -152,6 +152,12 @@ export default defineComponent({
if (status === 1 && i.action === 'build') {
return false;
}
if(i.action === 'save' && props.info.template_type === 1) {
return false
}
if(i.action === 'copy' && props.info.template_type === 1) {
return false
}
return true;
});
});

View File

@@ -31,7 +31,9 @@
<template #status="{ record }">
<div
class="status-text"
:class="record.status == 0 ? 'blue' : record.status == 1 ? 'green' : 'gray'"
:class="
record.status == 0 ? 'blue' : record.status == 1 ? 'green' : 'gray'
"
>
{{ record.status_txt }}
</div>
@@ -43,7 +45,10 @@
@click="handleJumpTo($event, 'design', record.sn)"
>编辑</a-button
>
<a-button class="custom-button" type="link" @click="handleJumpTo($event, 'link', record.sn)"
<a-button
class="custom-button"
type="link"
@click="handleJumpTo($event, 'link', record.sn)"
>发布</a-button
>
<a-button
@@ -53,27 +58,86 @@
>分析</a-button
>
<a-dropdown>
<a class="ant-dropdown-link" style="display: inline-block" @click.prevent>
<a
class="ant-dropdown-link"
style="display: inline-block"
@click.prevent
>
更多
<DownOutlined />
</a>
<template #overlay>
<SurveyAction :info="record" @click-action="actionClick" @update="update" />
<SurveyAction
:info="record"
@click-action="actionClick"
@update="update"
/>
</template>
</a-dropdown>
</template>
<template #tag="{ record }">
<div v-for="item in record.tags" :key="item.id" style="display: inline-block">
<div
v-for="item in record.tags"
:key="item.id"
style="display: inline-block"
>
<!-- <div v-for="it in record.tag" :key="it.id" style="display:inline-block;"> -->
<a-tooltip v-if="record.tag.length > 2" placement="right" :title="record.titles">
<a-tooltip
v-if="record.tag.length > 2"
placement="right"
:title="record.titles"
>
<div style="display: flex; flex-direction: row">
<div :title="item.title" :style="countColor(item.color)" class="tagStyle">
<div
:title="item.title"
:style="countColor(item.color)"
class="tagStyle"
>
{{ item.title }}
</div>
<div class="tagOmit" v-if="record.tags.length == 1">...</div>
</div>
</a-tooltip>
<div v-else :title="item.title" :style="countColor(item.color)" class="tagStyle">
<div
v-else
:title="item.title"
:style="countColor(item.color)"
class="tagStyle"
>
{{ item.title }}
</div>
<!-- </div> -->
</div>
</template>
<template #templateTag="{ record }">
<div
v-for="item in record.template_tags"
:key="item.id"
style="display: inline-block"
>
<!-- <div v-for="it in record.tag" :key="it.id" style="display:inline-block;"> -->
<a-tooltip
v-if="record.template_tags.length > 2"
placement="right"
:title="record.titles"
>
<div style="display: flex; flex-direction: row">
<div
:title="item.title"
:style="countColor(item.color)"
class="tagStyle"
>
{{ item.title }}
</div>
<div class="tagOmit" v-if="record.template_tags.length == 1">...</div>
</div>
</a-tooltip>
<div
v-else
:title="item.title"
:style="countColor(item.color)"
class="tagStyle"
>
{{ item.title }}
</div>
<!-- </div> -->
@@ -81,7 +145,12 @@
</template>
<template #titles="{ record }">
<a-tooltip placement="right" :title="record.remarks || ''">
<div>{{ record.project_name }}</div>
<div>
<span>{{ record.project_name }}</span>
<span class="table-sell" v-if="record.template_tag"
>#{{ record.template_tag }}</span
>
</div>
</a-tooltip>
</template>
<!-- <template v-slot:footer>
@@ -145,7 +214,12 @@
/>
</a-modal>
<a-modal v-model:visible="visibleMove" title="移动至分组" :maskClosable="false" :footer="null">
<a-modal
v-model:visible="visibleMove"
title="移动至分组"
:maskClosable="false"
:footer="null"
>
<MoveGroup
:group-id="activeGroupId"
:info="groupInfo"
@@ -174,7 +248,12 @@
@update="update"
/>
<a-modal v-model:visible="tempVisible" width="80%" :maskClosable="false" :footer="null">
<a-modal
v-model:visible="tempVisible"
width="80%"
:maskClosable="false"
:footer="null"
>
<createFromTemplate @tempCreate="onTempCreate" />
</a-modal>
<SurveyDownload
@@ -229,7 +308,17 @@ const columns = [
dataIndex: "tag[0].title",
align: "center",
slots: {
customRender: "tag",
customRender: "templateTag",
},
width: 200,
},
{
title: "模板标签",
key: "template_tags[0].title",
dataIndex: "template_tags[0].title",
align: "center",
slots: {
customRender: "templateTag",
},
width: 200,
},
@@ -790,4 +879,8 @@ export default defineComponent({
.ant-table-title {
padding: 0 !important;
}
.table-sell {
color: $yili-default-color;
word-break: keep-all;
}
</style>

View File

@@ -0,0 +1,778 @@
<template>
<div class="create-survey">
<div class="create-survey-title" v-if="curTemp.type === 1">
<div class="create-survey-title-line"></div>
<div class="create-survey-title-text">问卷配置</div>
</div>
<a-form
ref="formRef"
:model="ruleForm"
:rules="rules"
:label-col="{ span: 4 }"
>
<a-form-item label="问卷名称" name="project_name">
<a-input
v-model:value="ruleForm.project_name"
@keydown.enter="onSubmit"
placeholder="请输入问卷名称"
:maxlength="30"
showCount
>
<template #suffix>
<span class="suffix">
{{ `${ruleForm.project_name.length} / 30` }}
</span>
</template>
</a-input>
</a-form-item>
<a-form-item label="问卷标签" name="tags" v-if="isShow">
<a-select
v-model:value="ruleForm.tags"
style="width: 100%"
mode="multiple"
placeholder="搜索或新建标签"
:filterOption="filterOption"
class="show-select"
>
<a-select-option
:value="item.id"
:label="item.title"
v-for="item in tagsList"
:key="item.id"
>
<div style="display: flex; justify-content: space-between">
<span :style="countColor(item.color)" :title="item.title">{{
item.title
}}</span>
<!-- <span class="icon">
<EditOutlined class="edit" @click.stop="edit(item)" />
<DeleteOutlined class="del" @click.stop="del(item.id)" />
</span> -->
</div>
</a-select-option>
<!-- <template #dropdownRender="{ menuNode: menu }">
<v-nodes :vnodes="menu" />
<a-divider />
<div
style="padding: 4px 8px; cursor: pointer"
@mousedown="(e) => e.preventDefault()"
@click="addTag"
>
<plus-outlined />
新建标签
</div>
</template> -->
</a-select>
</a-form-item>
<a-form-item label="问卷简介" name="remarks" v-if="isShow">
<a-textarea
v-model:value="ruleForm.remarks"
showCount
autoSize
:maxlength="150"
placeholder="请输入"
allowClear
/>
</a-form-item>
</a-form>
<template v-if="curTemp.type === 1">
<div class="create-survey-title">
<div class="create-survey-title-line"></div>
<div class="create-survey-title-text">口味关键属性配置</div>
</div>
<div class="create-survey-list">
<div
class="create-survey-list-item"
:class="{ 'create-survey-list-item-error': item.status }"
v-for="(item, index) in smellList"
:key="index"
>
<label class="create-survey-list-item-label">口味关键属性</label>
<div class="create-survey-list-item-right">
<div class="create-survey-list-item-right-input">
<a-input
v-model:value="item.taste_attr"
class="custom-input"
:maxlength="30"
showCount
placeholder="请输入口味关键属性"
@blur="tasteBlurHandle(item, index)"
>
<template #suffix>
<span class="suffix">
{{ `${item.taste_attr.length} / 30` }}
</span>
</template>
</a-input>
<i
v-if="smellList.length < 20"
class="iconfont addfont"
@click="addSmellHandle(index)"
>&#xe6c4;</i
>
<i
v-if="smellList.length > 1"
class="iconfont addfont"
@click="delSmellHandle(index)"
>&#xe6cd;</i
>
</div>
<div class="create-survey-list-item-right-text">
{{ item.text }}
</div>
</div>
</div>
</div>
<div class="create-survey-title">
<div class="create-survey-title-line"></div>
<div class="create-survey-title-text">包装关键性配置</div>
</div>
<div class="create-survey-list">
<div
class="create-survey-list-item"
:class="{ 'create-survey-list-item-error': item.status }"
v-for="(item, index) in packList"
:key="index"
>
<label class="create-survey-list-item-label">包装关键属性</label>
<div class="create-survey-list-item-right">
<div class="create-survey-list-item-right-input">
<a-input
v-model:value="item.package_attr"
class="custom-input"
showCount
:maxlength="30"
placeholder="请输入包装关键属性"
@blur="packBlurHandle(item, index)"
>
<template #suffix>
<span class="suffix">
{{ `${item.package_attr.length} / 30` }}
</span>
</template>
</a-input>
<i
v-if="packList.length < 20"
class="iconfont addfont"
@click="addPackHandle(index)"
>&#xe6c4;</i
>
<i
v-if="packList.length > 1"
class="iconfont addfont"
@click="delPackHandle(index)"
>&#xe6cd;</i
>
</div>
<div class="create-survey-list-item-right-text">
{{ item.text }}
</div>
</div>
</div>
</div>
</template>
<div class="create-survey-footer">
<a-button
class="custom-button"
style="margin-right: 12px"
type="default"
@click="$emit('cancel')"
>取消</a-button
>
<a-button
class="custom-button"
type="primary"
:loading="loading"
@click="onSubmit"
>确定</a-button
>
</div>
<a-modal
v-model:visible="visibleTags"
title="新建标签"
:destroyOnClose="true"
:footer="null"
>
<addTag @cancel="visibleTags = false" @update="addTagUpdata"></addTag>
</a-modal>
</div>
</template>
<script>
import {
defineComponent,
reactive,
ref,
watch,
onBeforeMount,
createVNode,
} from "vue";
import { useRouter } from "vue-router";
import { message, Modal } from "ant-design-vue";
import {
// PlusOutlined,
ExclamationCircleOutlined,
// EditOutlined,
// DeleteOutlined
} from "@ant-design/icons-vue";
import {
postSurvey,
renewSurvey,
getTagsList,
deleteTags,
useTempCreateProject,
} from "@/views/ProjectManage/api.js";
import addTag from "@/views/ProjectManage/components/addTag.vue";
import useEmitter from "@/composables/useEmitter";
export default defineComponent({
name: "CreateSurvey",
name: "CreateWord",
props: {
groupId: { type: Number, value: 0 },
info: { type: Object, default: () => {} },
temp_sn: { type: String, default: "" },
curTemp: { type: Object, default: () => {} },
groupList: {
type: Array,
required: true,
},
},
components: {
// PlusOutlined,
// EditOutlined,
// DeleteOutlined,
addTag,
// VNodes: (_, { attrs }) => {
// return attrs.vnodes;
// }
},
setup(props, context) {
const emitter = useEmitter();
const items = ref([]);
const router = useRouter();
const formRef = ref();
const tagsList = ref([]);
const loading = ref(false);
const isShow = ref(props.info.sn ? false : true);
// console.log(props.group_id);
const ruleForm = reactive({
project_name: props.info?.project_name || "",
tags: props.info?.tag || [],
group_id: props?.groupId || 0,
remarks: props.remarks || "",
});
const rules = {
project_name: [
{ required: true, message: "请输入问卷名称", trigger: "blur" },
{ min: 1, max: 30, message: "字数超过限制", trigger: "blur" },
],
};
const visibleTags = ref(false);
watch(
() => props,
() => {
ruleForm.group_id = props?.groupId || 0;
ruleForm.project_name = props.info?.project_name || "";
ruleForm.tags = props.info?.tag || "";
ruleForm.remarks = props.info?.remarks || "";
isShow.value = props.info.sn ? false : true;
},
{ deep: true }
// () => props.groupId,
// () => {
// ruleForm.group_id = props?.groupId || 0;
// },
// () => props.info,
// () => {
// ruleForm.project_name = props.info?.project_name || '';
// }
);
// 标签颜色
const countColor = (value) => {
let style = {};
switch (value) {
case 1:
style = {
color: "#4DB8FA",
border: "1px solid #4DB8FA",
padding: "0 5px",
"border-radius": "4px",
"line-height": "20px",
};
break;
case 2:
style = {
color: "#0CC126",
// 'border-color' : '#0CC126',
border: "1px solid #0CC126",
padding: "0 5px",
"border-radius": "4px",
"line-height": "20px",
};
break;
case 3:
style = {
color: "#FF8800",
// 'border-color' : '#FF8800',
border: "1px solid #FF8800",
padding: "0 5px",
"border-radius": "4px",
"line-height": "20px",
};
break;
case 4:
style = {
color: "#FF374F",
// 'border-color' : '#FF374F',
border: "1px solid #FF374F",
padding: "0 5px",
"border-radius": "4px",
"line-height": "20px",
};
break;
case 5:
style = {
color: "#1C6FFF",
// 'border-color' : '#1C6FFF',
border: "1px solid #1C6FFF",
padding: "0 5px",
"border-radius": "4px",
"line-height": "20px",
};
break;
case 6:
style = {
color: "#11AEA7",
// 'border-color' : '#11AEA7',
border: "1px solid #11AEA7",
padding: "0 5px",
"border-radius": "4px",
"line-height": "20px",
};
break;
case 7:
style = {
color: "#25D8C8",
// 'border-color' : '#25D8C8',
border: "1px solid #25D8C8",
padding: "0 5px",
"border-radius": "4px",
"line-height": "20px",
};
break;
case 8:
style = {
color: "#FECB0D",
// 'border-color' : '#FECB0D',
border: "1px solid #FECB0D",
padding: "0 5px",
"border-radius": "4px",
"line-height": "20px",
};
// break;
// case 9:
// style = {
// 'color' : '4DB8FA',
// 'border-color' : '4DB8FA',
// }
}
return style;
};
const toSub = async () => {
loading.value = true;
let data;
try {
if (props.info?.sn) {
// xiugai
data = await renewSurvey({ ...ruleForm, sn: props.info.sn });
context.emit("update");
} else {
// 模版添加
if (props.temp_sn) {
let params = {
...ruleForm,
};
if (props.curTemp.type === 1) {
params.taste_list = smellList.value.map((sl) => {
return { taste_attr: sl.taste_attr };
});
params.package_list = packList.value.map((sl) => {
return { package_attr: sl.package_attr };
});
}
useTempCreateProject(props.temp_sn, params).then((res) => {
context.emit("temPreview", res.data);
context.emit("update");
context.emit("close");
setTimeout(() => {
router.push({
path: "/survey/planet/design",
query: { sn: res.data.sn },
});
}, 300);
});
}
// 普通添加
else {
const queryData = JSON.parse(
JSON.stringify({
...ruleForm,
group_id: ruleForm?.group_id ?? props.groupId,
})
);
queryData.tags = queryData.tags.join();
const { data } = await postSurvey(queryData);
console.log(data, "----------------");
router.push({
path: "/survey/planet/design",
query: { sn: data.sn },
});
}
}
message.success("保存成功");
} catch (error) {
console.log(error);
// context.message.warning(
// error.data?.message || error.message || "服务器错误"
// );
} finally {
loading.value = false;
}
};
/** 获取项目标签列表 */
const getTagsListRequest = async (val) => {
try {
const { data } = await getTagsList();
tagsList.value = data;
} catch (error) {
context.message.error(
error.data?.message || error.message || "服务器错误"
);
}
};
// 删除
const delRequest = async (id) => {
try {
const { data } = await deleteTags(id);
getTagsListRequest();
} catch (error) {
console.log(error);
}
};
const del = (id) => {
Modal.confirm({
content: "删除后,此标签会从当前团队的所有问卷中移除,且无法恢复!",
icon: () => createVNode(ExclamationCircleOutlined),
cancelText: "取消",
okText: "确认",
zIndex: 100001,
onOk: () => {
delRequest(id);
},
});
};
const edit = (item) => {
context.emit("labelEdit", item);
};
const addItem = () => {
emitter.emit("addGroup");
};
const addTag = () => {
visibleTags.value = true;
};
const addTagUpdata = () => {
visibleTags.value = false;
getTagsListRequest();
};
const smellList = ref([
{
taste_attr: "",
status: false,
text: "",
},
]);
const packList = ref([
{
package_attr: "",
status: false,
text: "",
},
]);
const addSmellHandle = (index) => {
if (smellList.value.length === 20) return;
smellList.value.splice(index, 0, {
taste_attr: "",
status: true,
text: "",
});
};
const delSmellHandle = (index) => {
Modal.confirm({
title: "确定删除这个产品口味关键属性?",
content: "口味关键属性删除后无法恢复!",
cancelText: "取消",
okText: "确认",
onOk() {
smellList.value.splice(index, 1);
},
});
};
const addPackHandle = (index) => {
if (smellList.value.length === 20) return;
packList.value.splice(index, 0, {
package_attr: "",
status: true,
text: "",
});
};
const delPackHandle = (index) => {
Modal.confirm({
title: "确定删除这个包装关键属性?",
content: "包装关键属性删除后无法恢复!",
cancelText: "取消",
okText: "确认",
class: "custom-modal custom-modal-title-confirm-notice",
onOk() {
smellList.value.splice(index, 1);
},
});
};
const tasteBlurHandle = (item, index) => {
const hasSameAttr = smellList.value.find(
(sm, smIndex) => smIndex !== index && sm.taste_attr === item.taste_attr
);
if (item.taste_attr.length === 0) {
item.status = true;
item.text = "口味属性不能为空";
} else if (hasSameAttr) {
item.status = true;
item.text = "口味属性不能重复";
} else {
item.status = false;
}
};
const packBlurHandle = (item, index) => {
const hasSameAttr = packList.value.find(
(pk, pkIndex) =>
pkIndex !== index && pk.package_attr === item.package_attr
);
if (item.package_attr.length === 0) {
item.status = true;
item.text = "包装属性不能为空";
} else if (hasSameAttr) {
item.status = true;
item.text = "包装属性不能重复";
} else {
item.status = false;
}
};
const onSubmit = () => {
let attrStatus = false;
if (props.curTemp.type === 1) {
smellList.value.forEach((sm, index) => {
tasteBlurHandle(sm, index);
attrStatus = sm.status;
});
packList.value.forEach((pk, index) => {
packBlurHandle(pk, index);
attrStatus = pk.status;
});
}
formRef.value
.validate()
.then(() => {
if (attrStatus) return;
Modal.confirm({
title: "保存后方案配置无法编辑,请您再次确认已完成最终配置!",
cancelText: "取消",
okText: "确认",
class: "custom-modal",
icon: createVNode(ExclamationCircleOutlined),
async onOk() {
await toSub();
await getTagsListRequest();
},
});
})
.catch((error) => {
console.log("error", error);
});
};
function filterOption(inputValue, option) {
const reg = new RegExp(inputValue);
const result = reg.test(option.label);
console.log(result);
return result;
}
onBeforeMount(() => {
getTagsListRequest();
});
return {
formRef,
rules,
ruleForm,
onSubmit,
loading,
options: [],
del,
edit,
items,
addItem,
addTag,
tagsList,
filterOption,
getTagsListRequest,
visibleTags,
addTagUpdata,
countColor,
isShow,
smellList,
packList,
addSmellHandle,
delSmellHandle,
addPackHandle,
delPackHandle,
tasteBlurHandle,
packBlurHandle,
};
},
});
</script>
<style lang="scss" scoped>
.icon {
font-size: 16px;
.del {
margin: 0 10px;
}
}
.tags {
margin: 0 5px 5px;
min-width: 75px;
width: 48px;
height: 19px;
border-radius: 4px;
// position: relative;
box-sizing: border-box;
.title {
// position: absolute;
font-size: 12px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
line-height: 17px;
display: flex;
justify-content: center;
}
.tagStyle {
border-radius: 4px;
max-width: 120px;
padding: 0 5px;
margin: 0 5px;
display: inline-block;
border-width: 1px;
border-style: solid;
color: #4db8fa;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
.show-select {
.icon {
display: none !important;
}
}
.create-survey {
&-title {
display: flex;
align-items: center;
margin-bottom: 24px;
&-line {
width: 4px;
height: 16px;
background: #70b936;
border-radius: 0px 0px 0px 0px;
}
&-text {
font-size: 16px;
font-weight: 500;
color: #262626;
margin-left: 8px;
}
}
&-list {
&-item {
display: flex;
margin-bottom: 24px;
&-label {
position: relative;
display: inline-flex;
align-items: center;
height: 32px;
color: rgba(0, 0, 0, 0.85);
font-size: 14px;
margin-right: 12px;
word-break: keep-all;
&::before {
display: inline-block;
margin-right: 4px;
color: #ff4d4f;
font-size: 14px;
font-family: SimSun, sans-serif;
line-height: 1;
content: "*";
}
}
&-right {
position: relative;
flex: 1;
&-input {
display: flex;
align-items: center;
}
&-text {
position: absolute;
left: 0;
color: rgba(0, 0, 0, 0.45);
height: 0;
font-size: 14px;
line-height: 1.5715;
transition: all 0.3s cubic-bezier(0.215, 0.61, 0.355, 1);
overflow: hidden;
}
}
&-error {
.create-survey-list-item-right-text {
height: 24px;
color: #ff4d4f;
}
&::v-deep {
.custom-input {
border-color: #ff4d4f;
&:hover {
border-color: #ff4d4f;
}
}
}
}
.addfont {
margin-left: 10px;
cursor: pointer;
color: #bfbfbf;
&:hover {
color: #434343;
}
}
}
}
&-footer {
display: flex;
justify-content: flex-end;
padding-top: 24px;
}
}
::v-deep .ant-input-textarea-clear-icon {
margin: 4px 3px 0 0;
}
</style>

View File

@@ -26,7 +26,11 @@
<div v-else>{{ record?.title }}</div>
</template>
<template #tag="{ record }">
<div v-for="item in record.tag" :key="item.id" style="display: inline-block">
<div
v-for="item in record.tag"
:key="item.id"
style="display: inline-block"
>
<!-- <div v-for="it in record.tag" :key="it.id" style="display:inline-block;"> -->
<a-tooltip
v-if="(record.tag && record.tag.length > 2) || isOverstep"
@@ -34,13 +38,22 @@
:title="record.titles"
>
<div style="display: flex; flex-direction: row">
<div :title="item.title" :style="countColor(item.color)" class="tagStyle">
<div
:title="item.title"
:style="countColor(item.color)"
class="tagStyle"
>
{{ item.title }}
</div>
<div class="tagOmit" v-if="record.tags.length == 1">...</div>
</div>
</a-tooltip>
<div v-else :title="item.title" :style="countColor(item.color)" class="tagStyle">
<div
v-else
:title="item.title"
:style="countColor(item.color)"
class="tagStyle"
>
{{ item.title }}
</div>
<!-- </div> -->
@@ -50,13 +63,20 @@
<a-button type="link" @click="handlePreview(record)">预览</a-button>
<a-button type="link" @click="handleUse(record)">使用</a-button>
<a-dropdown>
<a class="ant-dropdown-link" style="display: inline-block" @click.prevent>
<a
class="ant-dropdown-link"
:class="{ 'ant-dropdown-link-disable': record.type === 1 }"
style="display: inline-block"
@click.prevent
>
更多
<DownOutlined />
</a>
<template #overlay>
<template #overlay v-if="record.type !== 1">
<a-menu>
<a-menu-item @click="handleRemove(record)">重命名模版</a-menu-item>
<a-menu-item @click="handleRemove(record)"
>重命名模版</a-menu-item
>
<a-menu-item>
<a-popconfirm
title="确定删除改模版?"
@@ -97,17 +117,64 @@
@showSizeChange="onShowSizeChange"
/>
</div>
<a-modal v-model:visible="createVisible" title="创建问卷" :footer="null">
<a-modal v-model:visible="createVisible" :footer="null">
<template v-if="curTemp?.type === 1" v-slot:title>
<div class="custom-head">
<div>创建问卷</div>
<a-tooltip
placement="rightTop"
:overlayStyle="{
'max-width': '500px',
}"
>
<template v-slot:title>
<div class="custom-head-tip">
<div class="custom-head-tip-fz14" style="margin-bottom: 8px">
说明
</div>
<div class="custom-head-tip-fz12" style="margin-bottom: 8px">
此处主要配置问卷内产品口味包装参与调研的关键属性您可以自定义关键属性其中口味和包装的关键属性分别不可重复且至少配置一个关键属性
</div>
<div class="custom-head-tip-fz12" style="margin-bottom: 16px">
您配置几个口味关键属性就会生成几道口味属性喜欢成都的题目配置几个包装关键属性就会生成几道包装属性喜欢程度的题目
</div>
<div class="custom-head-tip-fz14" style="margin-bottom: 8px">
示例
</div>
<div class="custom-head-tip-fz12" style="margin-bottom: 8px">
示例配置了一个口味关键属性甜味和一个包装关键属性高端创建的问卷中对应的题目见下图区别于普通题型固定题型会展示固定标签以及对应属性信息
</div>
<img
class="custom-head-tip-img"
:src="`${baseOss}/sell-example.png`"
/>
</div>
</template>
<i class="iconfont">&#xe792;</i>
</a-tooltip>
</div>
</template>
<template v-else v-slot:title>
<div class="custom-head">
<div>创建问卷</div>
</div>
</template>
<CreateSurvey
:temp_sn="temp_sn"
:info="info"
:group-list="ProjectGroupList"
:curTemp="curTemp"
@close="handleClose"
@cancel="handleClose"
@temPreview="toDisngnPage"
/>
</a-modal>
<a-modal v-model:visible="renameVisible" title="重命名模版" :footer="null" :sn="sn">
<a-modal
v-model:visible="renameVisible"
title="重命名模版"
:footer="null"
:sn="sn"
>
<ReName :sn="sn" @cancel="renameVisible = false" @update="update" />
</a-modal>
<a-modal v-model:visible="visibleMove" title="移动至分组" :footer="null">
@@ -118,14 +185,24 @@
@update="update"
/>
</a-modal>
<a-modal v-model:visible="editLabelVisible" title="编辑标签" :footer="null" :zIndex="100000">
<a-modal
v-model:visible="editLabelVisible"
title="编辑标签"
:footer="null"
:zIndex="100000"
>
<editLabel
:info="editLabelItem"
@cancel="editLabelVisible = false"
@update="editLabelUpdata"
/>
</a-modal>
<a-modal v-model:visible="preview_visible" width="80%" :footer="null" :destroyOnClose="true">
<a-modal
v-model:visible="preview_visible"
width="80%"
:footer="null"
:destroyOnClose="true"
>
<div class="top" style="margin-top: 20px">
<h2>预览问卷</h2>
</div>
@@ -139,16 +216,24 @@ import MoveGroup from "../components/MoveGroup";
import editLabel from "../components/editLabel.vue";
import ReName from "../components/ReName";
import TempPreview from "@views/ProjectManage/components/TempPreview";
import CreateSurvey from "@/views/ProjectManage/components/CreateSurvey";
import CreateSurvey from "../components/CreateSurveyCopy.vue";
import { getGroupList } from "@/api/template-market";
import { nextTick, defineComponent, ref, onBeforeMount, watch, getCurrentInstance } from "vue";
import {
nextTick,
defineComponent,
ref,
onBeforeMount,
watch,
getCurrentInstance,
} from "vue";
import { useRouter } from "vue-router";
import { DownOutlined } from "@ant-design/icons-vue";
import { delTemplate, getTemplateList } from "@/api/template-market";
import { getSurveySorts } from "@/views/ProjectManage/api.js";
import { baseOss } from "../../../config";
const router = useRouter();
const columns = [
{
@@ -236,6 +321,7 @@ export default defineComponent({
const preview_visible = ref(false);
const createVisible = ref(false);
const info = { sn: "" };
const curTemp = ref(null);
const table = ref(null);
watch(
@@ -409,7 +495,7 @@ export default defineComponent({
onBeforeMount(async () => {
page.value = props.pageIndex ? props.pageIndex : 1;
const { data } = await getSurveySorts(1);
if(data){
if (data) {
search.value.sort = data.sort || "";
}
getTemplates();
@@ -420,6 +506,7 @@ export default defineComponent({
};
function handleUse(record) {
temp_sn.value = record.sn;
curTemp.value = record;
createVisible.value = true;
}
// 标签颜色
@@ -491,6 +578,7 @@ export default defineComponent({
createVisible.value = false;
}
return {
baseOss,
table,
sn,
handleChangeTable,
@@ -530,6 +618,7 @@ export default defineComponent({
info,
ProjectGroupList,
handleClose,
curTemp,
};
},
});
@@ -612,6 +701,38 @@ export default defineComponent({
border: 1px solid #4db8fa;
color: #4db8fa;
}
.custom-head {
display: flex;
align-items: center;
font-size: 16px;
font-weight: 500;
color: #262626;
.iconfont {
line-height: 14px;
height: 16px;
margin-left: 9px;
color: $yili-default-color;
cursor: pointer;
&:hover {
opacity: 0.8;
}
}
&-tip {
padding: 14px 25px;
&-fz14 {
line-height: 22px;
font-size: 14px;
}
&-fz12 {
line-height: 22px;
font-size: 12px;
}
&-img {
width: 342px;
height: 166px;
}
}
}
:deep(.ant-table) {
width: 100%;
}
@@ -621,4 +742,8 @@ export default defineComponent({
.ant-table-title {
padding: 0 !important;
}
.ant-dropdown-link-disable {
color: rgba(0, 0, 0, 0.25);
cursor: not-allowed;
}
</style>

View File

@@ -1,9 +1,13 @@
<template>
<ConfigBaseItem class="config-content-type">
<ConfigBaseItem
class="config-content-type"
:class="{ 'config-content-type-disable': disable }"
>
<span class="flex-none">内容限制</span>
<a-select
v-model:value="selected"
:get-popup-container="(current) => current.parentNode"
:disabled="disable"
class="custom-select"
style="width: 128px"
>
@@ -39,6 +43,7 @@ export default defineComponent({
props: {
value: { type: [Number, String], default: 0 },
nameQues: { type: Boolean, default: false },
disable: { type: [Boolean, Number], default: false },
},
emits: ["update:value"],
setup(props, context) {
@@ -69,6 +74,11 @@ export default defineComponent({
</script>
<style scoped lang="scss">
.config-content-type {
&-disable {
color: #8c8c8c;
}
}
.flex-none {
flex: none;
}

View File

@@ -1,29 +1,34 @@
<template>
<ConfigBaseItem class="config-require">
<ConfigBaseItem
class="config-require"
:class="{ 'config-require-disable': disable }"
>
<span>{{ title }}</span>
<a-switch
v-bind="$attrs"
v-model:checked="isChecked"
:disabled="disable"
class="custom-switch"
/>
</ConfigBaseItem>
</template>
<script>
import { defineComponent, ref, watch } from 'vue';
import { defineComponent, ref, watch } from "vue";
import ConfigBaseItem from './ConfigBaseItem.vue';
import ConfigBaseItem from "./ConfigBaseItem.vue";
export default defineComponent({
name: 'ConfigRequire',
name: "ConfigRequire",
components: {
ConfigBaseItem
ConfigBaseItem,
},
props: {
checked: { type: [Boolean, Number], default: true },
title: { type: [String], default: () => '此题必答' }
title: { type: [String], default: () => "此题必答" },
disable: { type: [Boolean, Number], default: false },
},
emits: ['update:checked'],
emits: ["update:checked"],
setup(props, context) {
const isChecked = ref(true);
@@ -41,16 +46,25 @@ export default defineComponent({
if (!cur === !prev) {
return;
}
context.emit('update:checked', cur ? 1 : 0);
context.emit("update:checked", cur ? 1 : 0);
});
const titles = ref(props.title);
return {
isChecked,
titles
titles,
};
}
},
});
</script>
<style scoped lang="scss">
.config-require {
&-disable {
color: #8c8c8c;
}
&::v-deep .ant-switch-disabled {
background-color: #d5ebc3;
opacity: 1;
}
}
</style>

View File

@@ -1,5 +1,6 @@
<template>
<div class="base">
<div class="sell-verify">标签属性#{{ info?.question_value }}</div>
<div class="related-option" v-for="rel in relatedOption" :key="rel.id">
<i class="iconfont">&#xe759;</i>
<div class="related-option-title">
@@ -130,6 +131,10 @@ export default defineComponent({
margin-bottom: 25px;
flex: 1;
}
.sell-verify {
padding-left: 37px;
color: $yili-default-color;
}
.related-option {
display: flex;
font-size: 14px;

View File

@@ -42,7 +42,7 @@
:disabled="copyInfo.question_type == 23"
></question-tinymce>
<div class="card-icon">
<div class="card-icon-item">
<div class="card-icon-item" v-if="!disableMoveBtn">
<a-tooltip title="移动" :mouseEnterDelay="1" placement="top">
<i class="iconfont moverQues defaultIcon">&#xe71b;</i>
</a-tooltip>
@@ -67,7 +67,7 @@
<i class="iconfont defaultIcon" @click="openModal">&#xe784;</i>
</a-tooltip>
</div> -->
<div class="card-icon-item">
<div class="card-icon-item" v-if="!disableCopyBtn">
<a-tooltip title="复制" :mouseEnterDelay="1" placement="top">
<i class="iconfont defaultIcon" @click.stop="copyHandle(copyInfo)"
>&#xe6c6;</i
@@ -89,7 +89,7 @@
</template>
</a-dropdown>
</div>
<div class="card-icon-item">
<div class="card-icon-item" v-if="!disableDelBtn">
<a-tooltip title="删除" :mouseEnterDelay="1" placement="top">
<i class="iconfont defaultIcon" @click.stop="deleteHandle"
>&#xe6c5;</i
@@ -277,6 +277,15 @@ export default {
return ![104, 105].includes(props.info.question_type);
});
const disableMoveBtn = computed(() => {
return copyInfo.value.permissions?.disable_update || false;
});
const disableCopyBtn = computed(() => {
return copyInfo.value.permissions?.disable_copy || false;
});
const disableDelBtn = computed(() => {
return copyInfo.value.permissions?.disable_delete || false;
});
const store = useStore();
const stemEdit = ref(false);
const inputRef = ref(null);
@@ -408,6 +417,9 @@ export default {
showQues,
open3DIcon,
inputRef,
disableMoveBtn,
disableCopyBtn,
disableDelBtn,
quesBankVisible,
checkGroupInfo,

View File

@@ -1,12 +1,16 @@
<template>
<ConfigTitle :quiz-index="copyConfig.title" :title="title" />
<div class="choice-config">
<div class="choice-config-inline">
<div
class="choice-config-inline"
:class="{ 'choice-config-inline-disable': disableUpdateBtn }"
>
<span class="choice-config-label">此题必答</span>
<a-switch
v-model:checked="copyConfig.config.is_required"
:checkedValue="1"
:unCheckedValue="0"
:disabled="disableUpdateBtn"
@change="switchChange"
/>
</div>
@@ -31,6 +35,9 @@ export default {
const copyConfig = computed(() => {
return reactive(JSON.parse(JSON.stringify(props.config)));
});
const disableUpdateBtn = computed(() => {
return props.config.permissions?.disable_update || false;
});
const title = computed(() => {
const type = copyConfig.value?.config.quick_type || 0;
const str =
@@ -42,6 +49,7 @@ export default {
};
return {
copyConfig,
disableUpdateBtn,
title,
switchChange,
};
@@ -62,6 +70,13 @@ export default {
display: flex;
align-items: center;
justify-content: space-between;
&-disable {
color: #8c8c8c;
}
&::v-deep .ant-switch-disabled {
background-color: #d5ebc3;
opacity: 1;
}
}
&-label {
font-weight: bold;

View File

@@ -139,6 +139,7 @@
</template>
<template v-slot:footer>
<a-button
v-if="!disableUpdateBtn"
type="text"
class="custom-button"
@click="addOptionHandle(optionList.length - 1)"
@@ -148,10 +149,13 @@
<span style="margin-left: 6px">添加选项</span>
</div>
</a-button>
<related-option :info="info" />
<option-show :info="info" />
<related-option v-if="!disableUpdateBtn" :info="info" />
<option-show v-if="!disableUpdateBtn" :info="info" />
<logical :info="info" />
<BatchManageOptions :info="info"></BatchManageOptions>
<BatchManageOptions
v-if="!disableUpdateBtn"
:info="info"
></BatchManageOptions>
</template>
</QuesBaseItem>
</template>
@@ -207,6 +211,9 @@ export default {
}
return info;
});
const disableUpdateBtn = computed(() => {
return props.info.permissions?.disable_update || false;
});
const optionList = ref([]);
const checkGroups = ref([]);
/** 修改选项 */
@@ -356,6 +363,7 @@ export default {
);
return {
copyInfo,
disableUpdateBtn,
optionList,
checkGroups,
editChange,

View File

@@ -13,7 +13,10 @@
:checked="copyConfig.config.select_random"
@update:checked="update('select_random', $event)"
/>
<ConfigBaseItem v-if="copyConfig.config.is_show.includes('question_type')" class="block">
<ConfigBaseItem
v-if="copyConfig.config.is_show.includes('question_type')"
class="block"
>
<div class="title">选择题型</div>
<div class="row">
<a-radio-group
@@ -36,7 +39,10 @@
@update:min="update('min_select', $event)"
@update:max="update('max_select', $event)"
/>
<ConfigBaseItem v-if="copyConfig.config.is_show.includes('each_number')" class="block">
<ConfigBaseItem
v-if="copyConfig.config.is_show.includes('each_number')"
class="block"
>
<div class="row">
<span class="choice-config-label">每行列数</span>
<a-tooltip title="最大为3列">
@@ -56,25 +62,39 @@
<template v-else>
<ConfigRequire
:checked="copyConfig.config.is_required"
:disable="disableUpdateBtn"
@update:checked="update('is_required', $event)"
/>
<ConfigRequire
title="选项随机"
:checked="copyConfig.config.select_random"
:disable="disableUpdateBtn"
@update:checked="update('select_random', $event)"
/>
<ConfigBaseItem class="block">
<div class="title">选择题型</div>
<div class="title" :class="{ 'disable-btn': disableUpdateBtn }">
选择题型
</div>
<div class="row">
<a-radio-group
v-model:value="copyConfig.question_type"
name="radioGroup"
:disabled="disableUpdateBtn"
@change="radioChange"
>
<a-radio style="margin-right: 32px" class="custom-radio" :value="1"
>单选题</a-radio
>
<a-radio class="custom-radio" :value="2">多选题</a-radio>
<a-radio
style="margin-right: 32px"
class="custom-radio"
:class="{ 'disable-btn': disableUpdateBtn }"
:value="1"
>单选题
</a-radio>
<a-radio
class="custom-radio"
:class="{ 'disable-btn': disableUpdateBtn }"
:value="2"
>多选题
</a-radio>
</a-radio-group>
</div>
</ConfigBaseItem>
@@ -116,8 +136,8 @@ import ConfigBaseItem from "../../components/config/ConfigBaseItem.vue";
import Config3D from "../../components/config/Config3D.vue";
import { useStore } from "vuex";
import { newQuesConfig } from "../../mode/index";
import ConfigOptionCount from '../../components/config/ConfigOptionCount.vue';
import { quickQuesTypeList } from '../../../../../utils/common.js';
import ConfigOptionCount from "../../components/config/ConfigOptionCount.vue";
import { quickQuesTypeList } from "../../../../../utils/common.js";
export default {
name: "ChoiceConfig",
components: { ConfigTitle, ConfigRequire, ConfigBaseItem, ConfigOptionCount, Config3D },
@@ -133,6 +153,9 @@ export default {
const copyConfig = computed(() => {
return reactive(JSON.parse(JSON.stringify(props.config)));
});
const disableUpdateBtn = computed(() => {
return props.config.permissions?.disable_update || false;
});
const title = computed(() => {
const type = store.state?.common?.activeQuestion?.config.quick_type || 0;
const str =
@@ -180,6 +203,7 @@ export default {
};
return {
copyConfig,
disableUpdateBtn,
title,
radioChange,
update,
@@ -200,4 +224,7 @@ export default {
margin-left: 16px;
margin-right: 10px;
}
.disable-btn {
color: #8c8c8c;
}
</style>

View File

@@ -7,6 +7,7 @@
<ConfigRequire
v-if="is_show.includes('is_required')"
:checked="is_required"
:disable="disableUpdateBtn"
@update:checked="update('is_required', $event)"
/>
<ConfigContentType
@@ -25,8 +26,20 @@
:type="text_type"
:text="[1, 2].includes(text_type) ? '数值限制' : '字数限制'"
:hide-suffix="[1, 2].includes(text_type)"
:minParseType="[2].includes(text_type) ? 'float' : ([1].includes(text_type) ? 'int' : 'uint')"
:maxParseType="[2].includes(text_type) ? 'float' : ([1].includes(text_type) ? 'int' : 'uint')"
:minParseType="
[2].includes(text_type)
? 'float'
: [1].includes(text_type)
? 'int'
: 'uint'
"
:maxParseType="
[2].includes(text_type)
? 'float'
: [1].includes(text_type)
? 'int'
: 'uint'
"
@update:blurMin="update('min', $event)"
@update:blurMax="update('max', $event)"
/>
@@ -41,7 +54,7 @@
:max="4"
class="custom-input-number"
style="width: 98px"
:parser="val => Math.floor(val)"
:parser="(val) => Math.floor(val)"
@blur="update('decimal_few', decimal_few)"
/>
</ConfigBaseItem>
@@ -81,8 +94,20 @@
:type="text_type"
:text="[1, 2].includes(text_type) ? '数值限制' : '字数限制'"
:hide-suffix="[1, 2].includes(text_type)"
:minParseType="[2].includes(text_type) ? 'float' : ([1].includes(text_type) ? 'int' : 'uint')"
:maxParseType="[2].includes(text_type) ? 'float' : ([1].includes(text_type) ? 'int' : 'uint')"
:minParseType="
[2].includes(text_type)
? 'float'
: [1].includes(text_type)
? 'int'
: 'uint'
"
:maxParseType="
[2].includes(text_type)
? 'float'
: [1].includes(text_type)
? 'int'
: 'uint'
"
@update:blurMin="update('min', $event)"
@update:blurMax="update('max', $event)"
/>
@@ -94,7 +119,7 @@
:max="4"
class="custom-input-number"
style="width: 98px"
:parser="val => Math.floor(val)"
:parser="(val) => Math.floor(val)"
@blur="update('decimal_few', decimal_few)"
/>
</ConfigBaseItem>
@@ -220,7 +245,9 @@ export default defineComponent({
const is_show = computed(() => {
return store.state?.common?.activeQuestion?.config?.is_show || [];
});
const disableUpdateBtn = computed(() => {
return props.config.permissions?.disable_update || false;
});
const decimal_few = ref(0);
const line_type = ref(0);
const line_height = ref(1);
@@ -278,6 +305,7 @@ export default defineComponent({
is_show,
copyConfig,
updateConfig,
disableUpdateBtn,
};
},
});