Merge branch 'feature/feature-20250331-h5' of https://e.coding.yili.com/yldc/ylst/ylst-survey-h5 into feature/feature-20250331-h5
This commit is contained in:
3
components.d.ts
vendored
3
components.d.ts
vendored
@@ -2,7 +2,7 @@
|
||||
// @ts-nocheck
|
||||
// Generated by unplugin-vue-components
|
||||
// Read more: https://github.com/vuejs/core/pull/3399
|
||||
export {};
|
||||
export {}
|
||||
|
||||
/* prettier-ignore */
|
||||
declare module 'vue' {
|
||||
@@ -32,6 +32,7 @@ declare module 'vue' {
|
||||
VanGrid: typeof import('vant/es')['Grid']
|
||||
VanGridItem: typeof import('vant/es')['GridItem']
|
||||
VanIcon: typeof import('vant/es')['Icon']
|
||||
VanList: typeof import('vant/es')['List']
|
||||
VanNavBar: typeof import('vant/es')['NavBar']
|
||||
VanPicker: typeof import('vant/es')['Picker']
|
||||
VanPopup: typeof import('vant/es')['Popup']
|
||||
|
||||
@@ -22,6 +22,20 @@ export function getSurveysPage(params) {
|
||||
params
|
||||
});
|
||||
}
|
||||
// 复制问卷
|
||||
export function copySurveys(sn) {
|
||||
return request({
|
||||
url: `/console/surveys/${sn}`,
|
||||
method: 'post'
|
||||
});
|
||||
}
|
||||
// 复制问卷
|
||||
export function deleteSurveys(sn) {
|
||||
return request({
|
||||
url: `/console/surveys/${sn}`,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
export function getListScene(params) {
|
||||
return request({
|
||||
url: 'console/h5_scene',
|
||||
@@ -51,3 +65,11 @@ export function deleteTemplate(sn) {
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
// 保存为模板
|
||||
export function saveTemplates(sn, data) {
|
||||
return request({
|
||||
url: `/console/surveys/${sn}/templates`,
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* color palette from <https://github.com/vuejs/theme> */
|
||||
:root {
|
||||
--primary-color: rgb(111, 185, 55);
|
||||
--primary-color: #71b73c;
|
||||
--vt-c-white: #fff;
|
||||
--vt-c-white-soft: #f8f8f8;
|
||||
--vt-c-white-mute: #f2f2f2;
|
||||
@@ -16,6 +16,9 @@
|
||||
--vt-c-text-light-2: rgba(60, 60, 60, 0.66);
|
||||
--vt-c-text-dark-1: var(--vt-c-white);
|
||||
--vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
|
||||
--van-picker-confirm-action-color: var(--primary-color);
|
||||
--van-calendar-range-edge-background: var(--primary-color);
|
||||
--van-cascader-active-color: var(--primary-color);
|
||||
--status-bar-height: 20px;
|
||||
}
|
||||
|
||||
@@ -29,6 +32,7 @@
|
||||
--color-heading: var(--vt-c-text-light-1);
|
||||
--color-text: var(--vt-c-text-light-1);
|
||||
--section-gap: 160px;
|
||||
--el-select-input-focus-border-color: var(--primary-color);
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
|
||||
@@ -1,9 +1,20 @@
|
||||
// main.scss
|
||||
|
||||
/* eslint-disable */
|
||||
@import 'theme';
|
||||
|
||||
/* eslint-disable */
|
||||
@import 'base';
|
||||
@import '../../fonts/iconfont.css';
|
||||
@import '../../fonts/moblie/iconfont.css';
|
||||
|
||||
/* eslint-disable */
|
||||
@import 'public';
|
||||
|
||||
/* eslint-disable */
|
||||
@import '../../fonts/iconfont.css';
|
||||
|
||||
/* eslint-disable */
|
||||
@import '../../fonts/moblie/iconfont.css';
|
||||
|
||||
a,
|
||||
.green {
|
||||
padding: 3px;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// public.scss
|
||||
.van-nav-bar {
|
||||
z-index: 999;
|
||||
padding-top: calc(var(--status-bar-height) + 15px) !important;
|
||||
@@ -13,6 +14,7 @@
|
||||
|
||||
.van-popup--bottom.van-popup--round {
|
||||
border-radius: 10px 10px 0 0 !important;
|
||||
background: #f2f2f2;
|
||||
}
|
||||
|
||||
.van-radio-group {
|
||||
@@ -88,7 +90,7 @@
|
||||
bottom: -2px;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
border-bottom: 0.0267rem solid #ebedf0;
|
||||
border-bottom: 0.0267rem solid #fff;
|
||||
pointer-events: none;
|
||||
transform: scaleY(0.5);
|
||||
}
|
||||
@@ -115,6 +117,11 @@
|
||||
color: $theme-color;
|
||||
}
|
||||
|
||||
.van-dialog__confirm,
|
||||
.van-dialog__confirm:active {
|
||||
color: $theme-color;
|
||||
}
|
||||
|
||||
.round-group {
|
||||
overflow: hidden;
|
||||
margin: 13px 10px;
|
||||
@@ -125,3 +132,98 @@
|
||||
border-color: $theme-color;
|
||||
background-color: $theme-color;
|
||||
}
|
||||
|
||||
.van-grid-item__content {
|
||||
padding: 8px 10px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.yl-select {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
max-width: 95vw;
|
||||
}
|
||||
|
||||
.el-select__wrapper::after {
|
||||
content: '\e65b';
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 10px;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.el-select__suffix {
|
||||
display: none;
|
||||
}
|
||||
|
||||
// 自定义下拉箭头样式
|
||||
.el-select__caret {
|
||||
color: $theme-color; // 修改箭头颜色
|
||||
font-size: 18px; // 修改箭头大小
|
||||
transform: rotate(0deg); // 修改箭头旋转角度(默认是0度,展开时会旋转180度)
|
||||
}
|
||||
|
||||
.el-cascader__tags .el-tag {
|
||||
background: $theme-color;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.el-tag .el-tag__close {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.el-cascader-node.in-active-path,
|
||||
.el-cascader-node.is-active,
|
||||
.el-cascader-node.is-selectable.in-checked-path {
|
||||
color: $theme-color;
|
||||
}
|
||||
|
||||
.el-checkbox__inner:hover {
|
||||
border-color: $theme-color;
|
||||
}
|
||||
|
||||
.el-checkbox__input.is-checked .el-checkbox__inner,
|
||||
.el-checkbox__input.is-indeterminate .el-checkbox__inner {
|
||||
border-color: $theme-color;
|
||||
background: $theme-color;
|
||||
}
|
||||
|
||||
.el-input,
|
||||
.el-input__wrapper {
|
||||
background: #fafbfc;
|
||||
}
|
||||
|
||||
.el-select__caret.is-reverse {
|
||||
transform: rotate(180deg); // 展开时旋转180度
|
||||
}
|
||||
|
||||
.el-select {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.el-select__wrapper {
|
||||
background: #fafbfc;
|
||||
}
|
||||
|
||||
.el-select-dropdown__item.is-selected {
|
||||
color: $theme-color;
|
||||
}
|
||||
|
||||
input {
|
||||
outline-color: transparent;
|
||||
}
|
||||
.el-input__wrapper,
|
||||
.el-select__wrapper {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.el-cascader .el-input.is-focus .el-input__wrapper,
|
||||
.el-input__wrapper.is-focus,
|
||||
.el-select__wrapper.is-focused,
|
||||
.el-cascader:not(.is-disabled):hover .el-input__wrapper {
|
||||
box-shadow: 0 0 0 0.0267rem $theme-color inset;
|
||||
|
||||
&::after {
|
||||
color: $theme-color;
|
||||
}
|
||||
}
|
||||
|
||||
BIN
src/assets/img/publish/edit.png
Normal file
BIN
src/assets/img/publish/edit.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.3 KiB |
BIN
src/assets/img/publish/end.png
Normal file
BIN
src/assets/img/publish/end.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.5 KiB |
BIN
src/assets/img/publish/publish.png
Normal file
BIN
src/assets/img/publish/publish.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.1 KiB |
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<el-select
|
||||
v-model="selectedValue"
|
||||
class="yl-select-wrapper"
|
||||
class="yl-select-wrapper mobilefont"
|
||||
popper-class="yl-select"
|
||||
@change="handleChange"
|
||||
>
|
||||
@@ -83,10 +83,14 @@ export default defineComponent({
|
||||
<style scoped lang="scss">
|
||||
.yl-select-wrapper {
|
||||
position: relative;
|
||||
outline-color: transparent;
|
||||
border-color: transparent;
|
||||
display: inline-block;
|
||||
font-size: 16px; /* 增加字体大小 */
|
||||
line-height: 1.5; /* 增加行高 */
|
||||
//margin-botton: 10px;
|
||||
padding: 2px 0;
|
||||
background: #fafbfc;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.yl-select-label {
|
||||
@@ -97,9 +101,6 @@ export default defineComponent({
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
.yl-select {
|
||||
overflow: hidden;
|
||||
max-width: 95vw;
|
||||
}
|
||||
<style lang="scss">
|
||||
@import '@/assets/css/theme';
|
||||
</style>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
@font-face {
|
||||
font-family: mobilefont; /* Project id 4841764 */
|
||||
src:
|
||||
url('iconfont.woff2?t=1742191207096') format('woff2'),
|
||||
url('iconfont.woff?t=1742191207096') format('woff'),
|
||||
url('iconfont.ttf?t=1742191207096') format('truetype');
|
||||
url('iconfont.woff2?t=1742213166999') format('woff2'),
|
||||
url('iconfont.woff?t=1742213166999') format('woff'),
|
||||
url('iconfont.ttf?t=1742213166999') format('truetype');
|
||||
}
|
||||
|
||||
.mobilefont {
|
||||
@@ -14,6 +14,18 @@
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.mobilefont-xiala::before {
|
||||
content: '\e65b';
|
||||
}
|
||||
|
||||
.mobilefont-upload::before {
|
||||
content: '\e682';
|
||||
}
|
||||
|
||||
.mobilefont-shanchu1::before {
|
||||
content: '\ed1b';
|
||||
}
|
||||
|
||||
.mobilefont-left-long::before {
|
||||
content: '\e601';
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -5,6 +5,27 @@
|
||||
"css_prefix_text": "mobilefont-",
|
||||
"description": "",
|
||||
"glyphs": [
|
||||
{
|
||||
"icon_id": "6548548",
|
||||
"name": "下拉",
|
||||
"font_class": "xiala",
|
||||
"unicode": "e65b",
|
||||
"unicode_decimal": 58971
|
||||
},
|
||||
{
|
||||
"icon_id": "15838548",
|
||||
"name": "upload",
|
||||
"font_class": "upload",
|
||||
"unicode": "e682",
|
||||
"unicode_decimal": 59010
|
||||
},
|
||||
{
|
||||
"icon_id": "24737052",
|
||||
"name": "删除",
|
||||
"font_class": "shanchu1",
|
||||
"unicode": "ed1b",
|
||||
"unicode_decimal": 60699
|
||||
},
|
||||
{
|
||||
"icon_id": "36915584",
|
||||
"name": "left-long",
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -121,8 +121,6 @@ const canPlanetPublishMxdAndHotArea = function (data) {
|
||||
* @returns
|
||||
*/
|
||||
const canPlanetPublish3D = function (data) {
|
||||
console.log(56, data);
|
||||
|
||||
{
|
||||
let canFB = true;
|
||||
let message = '';
|
||||
@@ -136,7 +134,9 @@ const canPlanetPublish3D = function (data) {
|
||||
canFB = false;
|
||||
qSteams.push(`(${s.title})`);
|
||||
}
|
||||
} catch (error) {}
|
||||
} catch (error) {
|
||||
// error
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -48,7 +48,9 @@ const router = createRouter({
|
||||
{
|
||||
path: '/preview',
|
||||
name: 'preview',
|
||||
meta: {},
|
||||
meta: {
|
||||
title: '预览'
|
||||
},
|
||||
component: () => import('@/views/Survey/views/Preview/Index.vue')
|
||||
},
|
||||
{
|
||||
|
||||
@@ -7,7 +7,7 @@ export default {
|
||||
options: [
|
||||
[
|
||||
{
|
||||
id: 'b68d45eb-d833-4b25-b0aa-2fde1310e88d',
|
||||
id: '',
|
||||
is_fixed: 0,
|
||||
is_other: 0,
|
||||
is_remove_other: 0,
|
||||
|
||||
@@ -121,6 +121,7 @@
|
||||
position="bottom"
|
||||
closeable
|
||||
close-icon="close"
|
||||
class="popup-bk"
|
||||
round
|
||||
:style="{ minHeight: '50%', maxHeight: '75%' }"
|
||||
@close="saveLogics"
|
||||
@@ -320,6 +321,10 @@ const updateConfig = (value) => {
|
||||
//max-width: 90vw;
|
||||
}
|
||||
|
||||
.popup-bk {
|
||||
background-color: #fff !important;
|
||||
}
|
||||
|
||||
.question-action-container {
|
||||
font-size: 20px;
|
||||
|
||||
|
||||
@@ -235,7 +235,8 @@ const textTypeList = [
|
||||
const emit = defineEmits(['update:modelValue', 'saveOption']);
|
||||
//
|
||||
const selectText = (textType) => {
|
||||
return textTypeList.filter((item) => item.value === textType)[0].text;
|
||||
let item = textTypeList.filter((item) => item.value === textType)[0];
|
||||
return item ? item.text : '';
|
||||
};
|
||||
const confirm = ({ selectedValues }) => {
|
||||
actionQuestion.value.config.text_type = Number(selectedValues[0]);
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
>
|
||||
<div class="mt10">
|
||||
<template v-for="(log, logIndex) in item.logic" :key="logIndex">
|
||||
<div class=" ">
|
||||
<div>
|
||||
<div class="question-before mb10">
|
||||
<div>
|
||||
<div class="logics-content">
|
||||
<!-- 固定分组-->
|
||||
<!-- if always-->
|
||||
<yl-select
|
||||
@@ -282,52 +282,24 @@
|
||||
</template>
|
||||
</BeforeMartrixComplation>
|
||||
</div>
|
||||
|
||||
<!-- <div class="action">-->
|
||||
<!-- <van-icon-->
|
||||
<!-- v-if="logIndex !== 0 || log.logic === 'always'"-->
|
||||
<!-- name="clear"-->
|
||||
<!-- class="mr10"-->
|
||||
<!-- @click="deleteLogic(logIndex, item.logic, index)"-->
|
||||
<!-- ></van-icon>-->
|
||||
<!-- <van-icon-->
|
||||
<!-- v-if="log.logic !== 'always'"-->
|
||||
<!-- name="add"-->
|
||||
<!-- @click="addLogicItem(logIndex, item.logic)"-->
|
||||
<!-- ></van-icon>-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
</template>
|
||||
<!-- 如果是题前隐藏-->
|
||||
<div v-if="skipType === 1">隐藏本题</div>
|
||||
<div v-if="skipType === 1" class="tip-text">隐藏本题</div>
|
||||
<!-- 如果是题后跳转-->
|
||||
<div v-if="skipType === 0" class="flex align-center space-between">
|
||||
<div class="jump-text mr10">跳转到</div>
|
||||
<div v-if="skipType === 0" class="">
|
||||
<div class="jump-text mr10 tip-text">跳转到</div>
|
||||
<yl-select
|
||||
v-model="item.skip_question_index"
|
||||
class="skip-select"
|
||||
class="skip-select mt10"
|
||||
:options="skipOption"
|
||||
></yl-select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- <van-divider-->
|
||||
<!-- :dashed="true"-->
|
||||
<!-- :hairline="false"-->
|
||||
<!-- content-position="right"-->
|
||||
<!-- :style="{ borderColor: '#bfbfbf' }"-->
|
||||
<!-- >-->
|
||||
<!-- <van-icon name="delete" @click="remoteLogic(index)">删除</van-icon>-->
|
||||
<!-- </van-divider>-->
|
||||
<!-- <div-->
|
||||
<!-- v-if="item.skip_type === skipType && item.question_index === activeQuestion.question_index"-->
|
||||
<!-- >-->
|
||||
<!-- del-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
</template>
|
||||
<div class="text-center">
|
||||
<van-button size="small" @click="addLogic">添加逻辑</van-button>
|
||||
<div class="text-center mt10">
|
||||
<van-button class="add-action-btn br12" size="small" @click="addLogic">添加逻辑</van-button>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
@@ -497,6 +469,13 @@ const logicIf = (value, index) => {
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '@/assets/css/theme';
|
||||
|
||||
.logics-content {
|
||||
border-color: transparent;
|
||||
outline-color: transparent;
|
||||
}
|
||||
|
||||
.flex1 {
|
||||
flex: 1;
|
||||
}
|
||||
@@ -526,6 +505,20 @@ const logicIf = (value, index) => {
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
.tip-text {
|
||||
color: #000;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.add-action-btn {
|
||||
height: 35px;
|
||||
padding: 12px 18px;
|
||||
border: none;
|
||||
background: rgba(240, 248, 235, 1);
|
||||
color: $theme-color;
|
||||
}
|
||||
|
||||
.question-before {
|
||||
width: 100%;
|
||||
|
||||
|
||||
@@ -64,6 +64,8 @@ const emitValue = () => {
|
||||
:label="element.stem"
|
||||
:required="element.config.is_required === 1"
|
||||
label-align="top"
|
||||
input-align="center"
|
||||
class="contenteditable-question-title"
|
||||
>
|
||||
<template #left-icon>
|
||||
{{ index + 1 }}
|
||||
@@ -79,8 +81,8 @@ const emitValue = () => {
|
||||
|
||||
<template #input>
|
||||
<div class="file-upload-label">
|
||||
<van-icon name="photo"></van-icon>
|
||||
<span>上传文件</span>
|
||||
<van-icon class-prefix="mobilefont" name="upload " />
|
||||
<span>文件上传</span>
|
||||
</div>
|
||||
</template>
|
||||
</van-field>
|
||||
@@ -90,12 +92,20 @@ const emitValue = () => {
|
||||
<style lang="scss" scoped>
|
||||
.file-upload-label {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
|
||||
//width: 100%;
|
||||
height: 50px;
|
||||
padding: 5px;
|
||||
border: 1px solid #dfdfdf;
|
||||
border-radius: 3px;
|
||||
margin: 60px 0;
|
||||
padding: 16px 18px;
|
||||
border: 1px dashed #979797;
|
||||
border-radius: 8px;
|
||||
color: #666;
|
||||
|
||||
//gap: 10px;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,38 +1,38 @@
|
||||
<script setup lang="ts">
|
||||
import { useTemplateRef, toRefs } from 'vue';
|
||||
import { /* useTemplateRef, */ ref, computed, type Component } from 'vue';
|
||||
import MatrixCheckbox from '@/views/Design/components/Questions/MatrixCheckbox.vue';
|
||||
import MatrixText from '@/views/Design/components/Questions/MatrixText.vue';
|
||||
import MatrixRadio from '@/views/Design/components/Questions/MatrixRadio.vue';
|
||||
|
||||
const columnLabels = useTemplateRef<HTMLElement[]>('columnLabels');
|
||||
const question = defineModel<question>('element', { default: () => ({}), required: false });
|
||||
// eslint-disable-next-line
|
||||
const activeComponent = computed<Component>(() => {
|
||||
switch (question.value.question_type) {
|
||||
case 8:
|
||||
return MatrixText;
|
||||
case 9:
|
||||
return MatrixRadio;
|
||||
case 10:
|
||||
return MatrixCheckbox;
|
||||
}
|
||||
});
|
||||
|
||||
if (question.value?.list) question.value.options = question.value?.list;
|
||||
// 行标签
|
||||
const rows = ref(question.value?.options[0] ?? []);
|
||||
// 列标签
|
||||
const cols = ref(question.value?.options[1] ?? []);
|
||||
|
||||
console.log(rows.value, cols.value);
|
||||
// const columnLabels = useTemplateRef<HTMLElement[]>('columnLabels');
|
||||
|
||||
// 注意, element.options 里面的东西是数组,第一项内容是行标签内容,第二项内容是列标签内容
|
||||
// 类型 AI 生成 切勿盲目相信,以实际为准
|
||||
const props = defineProps<{
|
||||
element: any;
|
||||
/* const props = */ defineProps<{
|
||||
index: number;
|
||||
active: boolean;
|
||||
}>();
|
||||
|
||||
const { element } = toRefs(props);
|
||||
/**
|
||||
* input 类型映射,里面自行处理逻辑返回对应类型
|
||||
* // remark: 填空内容 question_type 8
|
||||
* // remark: 单选打分矩阵 question_type 9
|
||||
* // remark: 多选矩阵内容 question_type 10
|
||||
* @default 'radio'
|
||||
*/
|
||||
const tableInputTypeMapping = (/** regx?: any */) => {
|
||||
switch (element.value.question_type) {
|
||||
case 8:
|
||||
return 'text';
|
||||
case 9:
|
||||
return 'radio';
|
||||
case 10:
|
||||
return 'checkbox';
|
||||
default:
|
||||
return 'radio';
|
||||
}
|
||||
};
|
||||
|
||||
const emit = defineEmits(['update:element']);
|
||||
const emitValue = () => {
|
||||
emit('update:element', element.value);
|
||||
};
|
||||
@@ -50,67 +50,74 @@ const emitValue = () => {
|
||||
</template>
|
||||
<!-- 使用 title 插槽来自定义标题 -->
|
||||
<template #label>
|
||||
<contenteditable v-model="element.stem" :active="active" @blur="emitValue"></contenteditable>
|
||||
<h1>
|
||||
<contenteditable v-model="element.stem" :active="active" @blur="emitValue" />
|
||||
</h1>
|
||||
</template>
|
||||
|
||||
<!-- 使用 label 插槽来自定义标题 -->
|
||||
<template #input>
|
||||
<table class="martrix-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<!-- 第一行内容为空 -->
|
||||
<th></th>
|
||||
<!-- 第二行内容开始填充 -->
|
||||
<td v-for="col in element.options[1]" :key="col.option" ref="columnLabels">
|
||||
<contenteditable
|
||||
v-model="col.option"
|
||||
:active="active"
|
||||
@blur="emitValue"
|
||||
></contenteditable>
|
||||
</td>
|
||||
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="row in element.options[0]" :key="row.option">
|
||||
<!-- 编辑状态,单次点击出输入框,失焦后关闭 -->
|
||||
<td>
|
||||
<contenteditable
|
||||
v-model="row.option"
|
||||
:active="active"
|
||||
@blur="emitValue"
|
||||
></contenteditable>
|
||||
</td>
|
||||
<td v-for="col in element.options[1]" :key="col.option" class="td-input">
|
||||
<!-- 编辑状态,单次点击出输入框,失焦后关闭 -->
|
||||
<input :id="col.option" :type="tableInputTypeMapping()" :name="row.option" />
|
||||
</td>
|
||||
|
||||
<td v-if="element.config.is_limit_right_content === 1">
|
||||
<contenteditable
|
||||
v-model="row.option_config.limit_right_content"
|
||||
:active="active"
|
||||
@blur="emitValue"
|
||||
>
|
||||
</contenteditable>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<Component :is="activeComponent" v-model:rows="rows" v-model:cols="cols" />
|
||||
</template>
|
||||
<!-- 使用 label 插槽来自定义标题 -->
|
||||
<!-- <template #input>-->
|
||||
<!-- <table class="matrix-table">-->
|
||||
<!-- <thead>-->
|
||||
<!-- <tr>-->
|
||||
<!-- <!– 第一行内容为空 –>-->
|
||||
<!-- <th></th>-->
|
||||
<!-- <!– 第二行内容开始填充 –>-->
|
||||
<!-- <td v-for="col in element.options[1]" :key="col.option" ref="columnLabels">-->
|
||||
<!-- <contenteditable-->
|
||||
<!-- v-model="col.option"-->
|
||||
<!-- :active="active"-->
|
||||
<!-- @blur="emitValue"-->
|
||||
<!-- ></contenteditable>-->
|
||||
<!-- </td>-->
|
||||
<!-- </tr>-->
|
||||
<!-- </thead>-->
|
||||
<!-- <tbody>-->
|
||||
<!-- <tr v-for="row in element.options[0]" :key="row.option">-->
|
||||
<!-- <!– 编辑状态,单次点击出输入框,失焦后关闭 –>-->
|
||||
<!-- <td>-->
|
||||
<!-- <contenteditable-->
|
||||
<!-- v-model="row.option"-->
|
||||
<!-- :active="active"-->
|
||||
<!-- @blur="emitValue"-->
|
||||
<!-- ></contenteditable>-->
|
||||
<!-- </td>-->
|
||||
<!-- <td v-for="col in element.options[1]" :key="col.option" class="td-input">-->
|
||||
<!-- <!– 编辑状态,单次点击出输入框,失焦后关闭 –>-->
|
||||
<!-- <input :id="col.option" :type="tableInputTypeMapping()" :name="row.option" />-->
|
||||
<!-- </td>-->
|
||||
|
||||
<!-- <td v-if="element.config.is_limit_right_content === 1">-->
|
||||
<!-- <contenteditable-->
|
||||
<!-- v-model="row.option_config.limit_right_content"-->
|
||||
<!-- :active="active"-->
|
||||
<!-- @blur="emitValue"-->
|
||||
<!-- >-->
|
||||
<!-- </contenteditable>-->
|
||||
<!-- </td>-->
|
||||
<!-- </tr>-->
|
||||
<!-- </tbody>-->
|
||||
<!-- </table>-->
|
||||
<!-- </template>-->
|
||||
</van-field>
|
||||
</template>
|
||||
<style scoped lang="scss">
|
||||
.martrix-table {
|
||||
<style lang="scss">
|
||||
.matrix-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
color: black;
|
||||
|
||||
& > tbody {
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
padding: 8px;
|
||||
border: 1px solid #ddd;
|
||||
//min-width: 80px;
|
||||
//padding: 8px;
|
||||
border-width: 0 0 1px;
|
||||
text-align: center;
|
||||
}
|
||||
@@ -130,6 +137,7 @@ input[type='text'] {
|
||||
input[type='checkbox'] {
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 5px;
|
||||
background-color: red;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
@@ -138,23 +146,4 @@ input[type='radio'] {
|
||||
border-radius: 5px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.martrix-table-action {
|
||||
margin-top: 10px;
|
||||
|
||||
.van-icon {
|
||||
color: lightgreen;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.martrix-table-action-tool {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
||||
& > span {
|
||||
margin-right: 6px;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -4,23 +4,27 @@
|
||||
<tr>
|
||||
<th></th>
|
||||
<td v-for="col in cols" :key="col.option">
|
||||
<contenteditable v-model="col.option" :active="active" @blur="emitValue" />
|
||||
|
||||
<!-- 编辑状态,单次点击出输入框,失焦后关闭 -->
|
||||
<input
|
||||
v-if="col.editor"
|
||||
v-model="col.option"
|
||||
v-focus
|
||||
type="text"
|
||||
@focusout="col.editor = false"
|
||||
@click="handleRowNameChange(col.option!)"
|
||||
/>
|
||||
<span v-else @click="handleRowNameChange(col.option!)" v-html="col.option"></span>
|
||||
<!-- <input-->
|
||||
<!-- v-if="col.editor"-->
|
||||
<!-- v-model="col.option"-->
|
||||
<!-- v-focus-->
|
||||
<!-- type="text"-->
|
||||
<!-- @focusout="col.editor = false"-->
|
||||
<!-- @click="handleRowNameChange(col.option!)"-->
|
||||
<!-- />-->
|
||||
<!-- <span v-else @click="handleRowNameChange(col.option!)" v-html="col.option"></span>-->
|
||||
</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(row, rowIndex) in rows" :key="rowIndex">
|
||||
<th v-html="row.option"></th>
|
||||
<td v-for="(col, colIndex) in cols" :key="colIndex">
|
||||
<!-- <th v-html="row.option"></th>-->
|
||||
<contenteditable v-model="row.option" :active="active" @blur="emitValue" />
|
||||
|
||||
<th v-for="(col, colIndex) in cols" :key="colIndex">
|
||||
<input
|
||||
type="checkbox"
|
||||
:name="`R${rowIndex + 1}`"
|
||||
@@ -28,15 +32,15 @@
|
||||
:checked="isOptionChecked(rowIndex, colIndex)"
|
||||
@change="handleMatrixRadioChange(rowIndex, colIndex)"
|
||||
/>
|
||||
</td>
|
||||
</th>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineProps } from 'vue';
|
||||
import { vFocus } from '@/utils/directives/useVFocus';
|
||||
// import { defineProps } from 'vue';
|
||||
// import { vFocus } from '@/utils/directives/useVFocus';
|
||||
|
||||
// 记录行和列的索引
|
||||
const rowRecord = defineModel<number[][]>('rowRecord', { required: false, default: () => [] });
|
||||
@@ -44,14 +48,16 @@ const rowRecord = defineModel<number[][]>('rowRecord', { required: false, defaul
|
||||
// 检查 rowRecord 是否存在
|
||||
// console.log(`rowRecord:`, rowRecord.value);
|
||||
|
||||
const active = defineModel('active', { required: false, default: true });
|
||||
/* const isPreview = */ defineModel<boolean>('isPreview', { required: false, default: false });
|
||||
defineProps<{
|
||||
rows: OptionType[];
|
||||
cols: OptionType[];
|
||||
}>();
|
||||
const rows = defineModel('rows', { required: false, default: () => [] });
|
||||
const cols = defineModel('cols', { required: false, default: () => [] });
|
||||
|
||||
// const emits = defineEmits(['update:matrixAnswer', 'update:rowRecord']);
|
||||
|
||||
const emitValue = () => {
|
||||
emit('update:element', element.value);
|
||||
};
|
||||
// 判断是否选中
|
||||
const isOptionChecked = (rowIndex: number, colIndex: number): boolean => {
|
||||
// [
|
||||
@@ -64,10 +70,10 @@ const isOptionChecked = (rowIndex: number, colIndex: number): boolean => {
|
||||
return rowRecord.value[rowIndex].includes(colIndex);
|
||||
};
|
||||
|
||||
const handleRowNameChange = (/* value: string */) => {
|
||||
// console.log(`row change: ${value}`);
|
||||
// 你可以在这里添加其他逻辑
|
||||
};
|
||||
// const handleRowNameChange = (/* value: string */) => {
|
||||
// // console.log(`row change: ${value}`);
|
||||
// // 你可以在这里添加其他逻辑
|
||||
// };
|
||||
|
||||
// 当 matrix radio 选中时,更新 rowRecord 和 matrixAnswer
|
||||
function handleMatrixRadioChange(row: number, col: number) {
|
||||
@@ -108,16 +114,4 @@ function handleMatrixRadioChange(row: number, col: number) {
|
||||
// };
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.matrix-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.matrix-table th,
|
||||
.matrix-table td {
|
||||
padding: 8px;
|
||||
border: 1px solid #ddd;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
<style scoped lang="scss"></style>
|
||||
|
||||
@@ -1,123 +1,127 @@
|
||||
<script setup lang="ts">
|
||||
import { useTemplateRef, ref, type Directive } from 'vue';
|
||||
// import MatrixRadio from '@/views/Design/components/Questions/MatrixRadio.vue';
|
||||
// import MatrixText from '@/views/Design/components/Questions/MatrixText.vue';
|
||||
// import MatrixCheckbox from '@/views/Design/components/Questions/MatrixCheckbox.vue';
|
||||
|
||||
const columnLabels = useTemplateRef<HTMLElement[]>('columnLabels');
|
||||
|
||||
// 注意, element.options 里面的东西是数组,第一项内容是行标签内容,第二项内容是列标签内容
|
||||
// 类型 AI 生成 切勿盲目相信,以实际为准
|
||||
const { element, index } = defineProps<{ element: MatrixSurveyQuestion; index: number }>();
|
||||
|
||||
const rowRecord = new Array(element.options[0].length);
|
||||
// matrix 答案
|
||||
const matrixAnswer = ref({
|
||||
question_index: index,
|
||||
answer: {} as any
|
||||
});
|
||||
|
||||
/**
|
||||
* input 类型映射,里面自行处理逻辑返回对应类型
|
||||
* // remark: 填空内容 question_type 8
|
||||
* // remark: 单选打分矩阵 question_type 9
|
||||
* // remark: 多选矩阵内容 question_type 10
|
||||
* @default 'radio'
|
||||
*/
|
||||
const tableInputTypeMapping = (/** regx?: any */) => {
|
||||
switch (element.question_type) {
|
||||
case 8:
|
||||
return 'text';
|
||||
case 9:
|
||||
return 'radio';
|
||||
case 10:
|
||||
return 'checkbox';
|
||||
default:
|
||||
return 'radio';
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 自定义指令,用于在元素挂载后自动获取焦点
|
||||
*/
|
||||
const vFocus: Directive = {
|
||||
mounted(el: HTMLInputElement) {
|
||||
el.focus();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* row 的数值变动之后,触发的事件
|
||||
* @param {string} value
|
||||
* @return {void}
|
||||
*/
|
||||
function handleRowNameChange(/* value: string */) {
|
||||
// if (!value) return;
|
||||
}
|
||||
|
||||
/**
|
||||
* col 的数值变动之后,触发的事件
|
||||
*/
|
||||
function handleColNameChange(rowOption: string, colOption: string, e: any) {
|
||||
// if (!value) return;
|
||||
const col = element.options[0].findIndex((option) => {
|
||||
return option.option === colOption;
|
||||
});
|
||||
|
||||
const row = element.options[1].findIndex((option) => {
|
||||
return option.option === rowOption;
|
||||
});
|
||||
|
||||
// 不同的 question_type 的 matrix 问卷处理不同的结果
|
||||
switch (element.question_type) {
|
||||
case 8: {
|
||||
// 获取输入框元素
|
||||
const inputElement = e.target as HTMLInputElement;
|
||||
// 如果没有获取到输入框元素,则直接返回
|
||||
if (!inputElement) return;
|
||||
// 将输入框的值保存到 rowRecord 对应位置
|
||||
rowRecord[col] = e!.target!.value;
|
||||
// 清空 matrixAnswer 的 answer 属性
|
||||
matrixAnswer.value.answer = {};
|
||||
// 遍历所有行选项
|
||||
element.options[0].forEach((_, rowIndex) => {
|
||||
// 获取当前行记录
|
||||
const colOptions = rowRecord[rowIndex];
|
||||
// 如果当前行有记录,则更新 matrixAnswer 的 answer 属性
|
||||
if (colOptions) {
|
||||
matrixAnswer.value.answer[`R${rowIndex + 1}_C${col + 1}`] = colOptions;
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
case 9:
|
||||
// 将选择的行索引加1后保存到 rowRecord 对应位置
|
||||
rowRecord[col] = row + 1;
|
||||
// 清空 matrixAnswer 的 answer 属性
|
||||
matrixAnswer.value.answer = {};
|
||||
// 遍历 rowRecord,更新 matrixAnswer 的 answer 属性
|
||||
rowRecord.forEach((row, index) => {
|
||||
matrixAnswer.value.answer[`${index + 1}_${row}`] = 1;
|
||||
});
|
||||
break;
|
||||
case 10:
|
||||
// 将选择的行索引加1后添加到 rowRecord 对应位置的数组中
|
||||
rowRecord[col] = (rowRecord[col] || []).concat(row + 1);
|
||||
// 清空 matrixAnswer 的 answer 属性
|
||||
matrixAnswer.value.answer = {};
|
||||
// 遍历所有行选项
|
||||
element.options[0].forEach((rowOption, rowIndex) => {
|
||||
// 获取当前行记录
|
||||
const colOptions = rowRecord[rowIndex];
|
||||
// 如果当前行有记录,则更新 matrixAnswer 的 answer 属性
|
||||
if (colOptions) {
|
||||
colOptions.forEach((col: any) => {
|
||||
matrixAnswer.value.answer[`R${rowIndex + 1}_C${col}`] = true;
|
||||
});
|
||||
}
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
// import { useTemplateRef, ref, type Directive } from 'vue';
|
||||
//
|
||||
// const columnLabels = useTemplateRef<HTMLElement[]>('columnLabels');
|
||||
//
|
||||
// // 注意, element.options 里面的东西是数组,第一项内容是行标签内容,第二项内容是列标签内容
|
||||
// // 类型 AI 生成 切勿盲目相信,以实际为准
|
||||
// const { element, index } = defineProps<{ element: MatrixSurveyQuestion; index: number }>();
|
||||
//
|
||||
// const rowRecord = new Array(element.options[0].length);
|
||||
// // matrix 答案
|
||||
// const matrixAnswer = ref({
|
||||
// question_index: index,
|
||||
// answer: {} as any
|
||||
// });
|
||||
//
|
||||
// /**
|
||||
// * input 类型映射,里面自行处理逻辑返回对应类型
|
||||
// * // remark: 填空内容 question_type 8
|
||||
// * // remark: 单选打分矩阵 question_type 9
|
||||
// * // remark: 多选矩阵内容 question_type 10
|
||||
// * @default 'radio'
|
||||
// */
|
||||
// const tableInputTypeMapping = (/** regx?: any */) => {
|
||||
// switch (element.question_type) {
|
||||
// case 8:
|
||||
// return 'text';
|
||||
// case 9:
|
||||
// return 'radio';
|
||||
// case 10:
|
||||
// return 'checkbox';
|
||||
// default:
|
||||
// return 'radio';
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// /**
|
||||
// * 自定义指令,用于在元素挂载后自动获取焦点
|
||||
// */
|
||||
// const vFocus: Directive = {
|
||||
// mounted(el: HTMLInputElement) {
|
||||
// el.focus();
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// /**
|
||||
// * row 的数值变动之后,触发的事件
|
||||
// * @param {string} value
|
||||
// * @return {void}
|
||||
// */
|
||||
// function handleRowNameChange(/* value: string */) {
|
||||
// // if (!value) return;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * col 的数值变动之后,触发的事件
|
||||
// */
|
||||
// function handleColNameChange(rowOption: string, colOption: string, e: any) {
|
||||
// // if (!value) return;
|
||||
// const col = element.options[0].findIndex((option) => {
|
||||
// return option.option === colOption;
|
||||
// });
|
||||
//
|
||||
// const row = element.options[1].findIndex((option) => {
|
||||
// return option.option === rowOption;
|
||||
// });
|
||||
//
|
||||
// // 不同的 question_type 的 matrix 问卷处理不同的结果
|
||||
// switch (element.question_type) {
|
||||
// case 8: {
|
||||
// // 获取输入框元素
|
||||
// const inputElement = e.target as HTMLInputElement;
|
||||
// // 如果没有获取到输入框元素,则直接返回
|
||||
// if (!inputElement) return;
|
||||
// // 将输入框的值保存到 rowRecord 对应位置
|
||||
// rowRecord[col] = e!.target!.value;
|
||||
// // 清空 matrixAnswer 的 answer 属性
|
||||
// matrixAnswer.value.answer = {};
|
||||
// // 遍历所有行选项
|
||||
// element.options[0].forEach((_, rowIndex) => {
|
||||
// // 获取当前行记录
|
||||
// const colOptions = rowRecord[rowIndex];
|
||||
// // 如果当前行有记录,则更新 matrixAnswer 的 answer 属性
|
||||
// if (colOptions) {
|
||||
// matrixAnswer.value.answer[`R${rowIndex + 1}_C${col + 1}`] = colOptions;
|
||||
// }
|
||||
// });
|
||||
// break;
|
||||
// }
|
||||
// case 9:
|
||||
// // 将选择的行索引加1后保存到 rowRecord 对应位置
|
||||
// rowRecord[col] = row + 1;
|
||||
// // 清空 matrixAnswer 的 answer 属性
|
||||
// matrixAnswer.value.answer = {};
|
||||
// // 遍历 rowRecord,更新 matrixAnswer 的 answer 属性
|
||||
// rowRecord.forEach((row, index) => {
|
||||
// matrixAnswer.value.answer[`${index + 1}_${row}`] = 1;
|
||||
// });
|
||||
// break;
|
||||
// case 10:
|
||||
// // 将选择的行索引加1后添加到 rowRecord 对应位置的数组中
|
||||
// rowRecord[col] = (rowRecord[col] || []).concat(row + 1);
|
||||
// // 清空 matrixAnswer 的 answer 属性
|
||||
// matrixAnswer.value.answer = {};
|
||||
// // 遍历所有行选项
|
||||
// element.options[0].forEach((rowOption, rowIndex) => {
|
||||
// // 获取当前行记录
|
||||
// const colOptions = rowRecord[rowIndex];
|
||||
// // 如果当前行有记录,则更新 matrixAnswer 的 answer 属性
|
||||
// if (colOptions) {
|
||||
// colOptions.forEach((col: any) => {
|
||||
// matrixAnswer.value.answer[`R${rowIndex + 1}_C${col}`] = true;
|
||||
// });
|
||||
// }
|
||||
// });
|
||||
// break;
|
||||
// default:
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -200,7 +204,7 @@ input[type='text'] {
|
||||
width: 85%;
|
||||
}
|
||||
|
||||
.martrix-table-action {
|
||||
.matrix-table-action {
|
||||
margin-top: 10px;
|
||||
|
||||
.van-icon {
|
||||
@@ -208,7 +212,7 @@ input[type='text'] {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.martrix-table-action-tool {
|
||||
.matrix-table-action-tool {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
||||
|
||||
@@ -3,26 +3,27 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<td v-for="col in cols" :key="col.option">
|
||||
<th v-for="col in cols" :key="col.option">
|
||||
<contenteditable v-model="col.option" :active="active" @blur="emitValue" />
|
||||
<!-- 编辑状态,单次点击出输入框,失焦后关闭 -->
|
||||
<input
|
||||
v-if="col.editor"
|
||||
v-model="col.option"
|
||||
v-focus
|
||||
type="text"
|
||||
@focusout="col.editor = false"
|
||||
@click="handleRowNameChange(col.option!)"
|
||||
/>
|
||||
<span v-else @click="handleRowNameChange(col.option!)" v-html="col.option"></span>
|
||||
</td>
|
||||
<!-- <input-->
|
||||
<!-- v-if="col.editor"-->
|
||||
<!-- v-model="col.option"-->
|
||||
<!-- v-focus-->
|
||||
<!-- type="text"-->
|
||||
<!-- @focusout="col.editor = false"-->
|
||||
<!-- @click="handleRowNameChange(col.option!)"-->
|
||||
<!-- />-->
|
||||
<!-- <span v-else @click="handleRowNameChange(col.option!)" v-html="col.option"></span>-->
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(row, rowIndex) in rows" :key="rowIndex">
|
||||
<th v-html="row.option"></th>
|
||||
<contenteditable v-model="row.option" :active="active" @blur="emitValue" />
|
||||
<td v-for="(col, colIndex) in cols" :key="colIndex">
|
||||
<input
|
||||
type=" "
|
||||
type="radio"
|
||||
:name="`R${rowIndex + 1}`"
|
||||
:value="`${rowIndex + 1}_${colIndex + 1}`"
|
||||
:checked="isOptionChecked(rowIndex, colIndex)"
|
||||
@@ -35,8 +36,8 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineProps } from 'vue';
|
||||
import { vFocus } from '@/utils/directives/useVFocus';
|
||||
// import { defineProps } from 'vue';
|
||||
// import { vFocus } from '@/utils/directives/useVFocus';
|
||||
|
||||
// 记录行和列的索引
|
||||
const rowRecord = defineModel<number[]>('rowRecord', { required: false, default: () => [] });
|
||||
@@ -45,11 +46,11 @@ const rowRecord = defineModel<number[]>('rowRecord', { required: false, default:
|
||||
// console.log(`rowRecord:`, rowRecord.value);
|
||||
|
||||
/* const isPreview = */ defineModel<boolean>('isPreview', { required: false, default: false });
|
||||
defineProps<{
|
||||
rows: OptionType[];
|
||||
cols: OptionType[];
|
||||
}>();
|
||||
|
||||
const rows = defineModel('rows', { required: false, default: () => [] });
|
||||
const cols = defineModel('cols', { required: false, default: () => [] });
|
||||
const active = defineModel('active', { required: false, default: true });
|
||||
console.log(rows.value, cols.value);
|
||||
// const emits = defineEmits(['update:matrixAnswer', 'update:rowRecord']);
|
||||
|
||||
// 判断是否选中
|
||||
@@ -62,10 +63,10 @@ const isOptionChecked = (rowIndex: number, colIndex: number): boolean => {
|
||||
// return !!matrixAnswer.value?.[key];
|
||||
};
|
||||
|
||||
const handleRowNameChange = (/* value: string */) => {
|
||||
// console.log(`row change: ${value}`);
|
||||
// 你可以在这里添加其他逻辑
|
||||
};
|
||||
// const handleRowNameChange = (/* value: string */) => {
|
||||
// // console.log(`row change: ${value}`);
|
||||
// // 你可以在这里添加其他逻辑
|
||||
// };
|
||||
|
||||
// 当 matrix radio 选中时,更新 rowRecord 和 matrixAnswer
|
||||
function handleMatrixRadioChange(row: number, col: number) {
|
||||
@@ -91,18 +92,9 @@ function handleMatrixRadioChange(row: number, col: number) {
|
||||
// emits('update:matrixAnswer', props.matrixAnswer);
|
||||
// emits('update:rowRecord', props.rowRecord);
|
||||
// };
|
||||
const emitValue = () => {
|
||||
emit('update:element', element.value);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.matrix-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.matrix-table th,
|
||||
.matrix-table td {
|
||||
padding: 8px;
|
||||
border: 1px solid #ddd;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
<style scoped lang="scss"></style>
|
||||
|
||||
@@ -3,23 +3,26 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<td v-for="col in cols" :key="col.option">
|
||||
<th v-for="col in cols" :key="col.option">
|
||||
<contenteditable v-model="col.option" :active="active" @blur="emitValue" />
|
||||
<!-- 编辑状态,单次点击出输入框,失焦后关闭 -->
|
||||
<input
|
||||
v-if="col.editor"
|
||||
v-model="col.option"
|
||||
v-focus
|
||||
type="text"
|
||||
@focusout="col.editor = false"
|
||||
@click="handleRowNameChange(col.option!)"
|
||||
/>
|
||||
<span v-else @click="handleRowNameChange(col.option!)" v-html="col.option"></span>
|
||||
</td>
|
||||
<!-- <input-->
|
||||
<!-- v-if="col.editor"-->
|
||||
<!-- v-model="col.option"-->
|
||||
<!-- v-focus-->
|
||||
<!-- type="text"-->
|
||||
<!-- @focusout="col.editor = false"-->
|
||||
<!-- @click="handleRowNameChange(col.option!)"-->
|
||||
<!-- />-->
|
||||
<!-- <span v-else @click="handleRowNameChange(col.option!)" v-html="col.option"></span>-->
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(row, rowIndex) in rows" :key="rowIndex">
|
||||
<th v-html="row.option"></th>
|
||||
<!-- <th v-html="row.option"></th>-->
|
||||
<contenteditable v-model="row.option" :active="active" @blur="emitValue" />
|
||||
|
||||
<td v-for="(col, colIndex) in cols" :key="colIndex">
|
||||
<input
|
||||
type="text"
|
||||
@@ -34,27 +37,23 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineProps } from 'vue';
|
||||
import { vFocus } from '@/utils/directives/useVFocus';
|
||||
|
||||
// 记录行和列的索引
|
||||
const rowRecord = defineModel<string[][]>('rowRecord', { required: false, default: () => [] });
|
||||
// const matrixAnswer = defineModel<{ [key: string]: 1 }>('matrixAnswer', { required: false, default: () => ({}) });
|
||||
// 检查 rowRecord 是否存在
|
||||
// console.log(`rowRecord:`, rowRecord.value);
|
||||
const active = defineModel('active', { required: false, default: true });
|
||||
|
||||
/* const isPreview = */ defineModel<boolean>('isPreview', { required: false, default: false });
|
||||
defineProps<{
|
||||
rows: OptionType[];
|
||||
cols: OptionType[];
|
||||
}>();
|
||||
const rows = defineModel('rows', { required: false, default: () => [] });
|
||||
const cols = defineModel('cols', { required: false, default: () => [] });
|
||||
|
||||
// const emits = defineEmits(['update:matrixAnswer', 'update:rowRecord']);
|
||||
|
||||
const handleRowNameChange = (/* value: string */) => {
|
||||
// console.log(`row change: ${value}`);
|
||||
// 你可以在这里添加其他逻辑
|
||||
};
|
||||
// const handleRowNameChange = (/* value: string */) => {
|
||||
// console.log(`row change: ${value}`);
|
||||
// 你可以在这里添加其他逻辑
|
||||
// };
|
||||
|
||||
function getInputValue(row: number, col: number) {
|
||||
// console.log(`row: ${row}, col: ${col}`);
|
||||
@@ -96,16 +95,4 @@ function handleMatrixTextChange(row: number, col: number, e: Event) {
|
||||
// };
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.matrix-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.matrix-table th,
|
||||
.matrix-table td {
|
||||
padding: 8px;
|
||||
border: 1px solid #ddd;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
<style scoped lang="scss"></style>
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
:label="element.stem"
|
||||
:required="element.config.is_required === 1"
|
||||
label-align="top"
|
||||
class="contenteditable-question-title"
|
||||
>
|
||||
<template #left-icon>
|
||||
{{ index + 1 }}
|
||||
@@ -16,25 +17,24 @@
|
||||
<div
|
||||
v-for="(optionItem, optionItemIndex) in isPreview ? element.list : element.options"
|
||||
:key="optionItemIndex"
|
||||
class="rate-content"
|
||||
>
|
||||
<div
|
||||
v-for="(item, optionIndex) in isPreview ? optionItem.options : optionItem"
|
||||
:key="optionIndex"
|
||||
@click="chooseOption(item)"
|
||||
>
|
||||
<RateCharacter
|
||||
v-model="rate"
|
||||
:index="optionIndex"
|
||||
:config="element.config"
|
||||
@change="handleRateChange"
|
||||
>
|
||||
</RateCharacter>
|
||||
<div class="tips">
|
||||
<div class="tips mb5">
|
||||
<p>{{ element.config.prompt_left }}</p>
|
||||
<p>{{ element.config.prompt_center }}</p>
|
||||
<p>{{ element.config.prompt_right }}</p>
|
||||
</div>
|
||||
<RateCharacter v-model="answerValue" :config="element.config"></RateCharacter>
|
||||
<RateCharacter
|
||||
v-model="answerValue"
|
||||
:config="element.config"
|
||||
:index="optionIndex"
|
||||
@change="handleRateChange"
|
||||
></RateCharacter>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -43,14 +43,11 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, toRefs } from 'vue';
|
||||
import { ref } from 'vue';
|
||||
import RateCharacter from './RateCharacter.vue';
|
||||
|
||||
const isPreview = defineModel('isPreview', { default: false, type: Boolean });
|
||||
const props = defineProps({
|
||||
element: {
|
||||
type: Object
|
||||
},
|
||||
index: {
|
||||
type: Number,
|
||||
default: 0
|
||||
@@ -66,6 +63,14 @@ const props = defineProps({
|
||||
// answer 的答案以 矩阵形式存储, 例如 [4,7],上层更新答案的时候也容易
|
||||
const rates = defineModel('rates', { default: [], type: Array });
|
||||
const rate = ref(0);
|
||||
const answerValue = ref();
|
||||
|
||||
const element = defineModel('element', {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
}
|
||||
});
|
||||
|
||||
// 不知道的 BUG ,开始的时候不能重置颜色。 故如此
|
||||
setTimeout(() => {
|
||||
@@ -92,7 +97,6 @@ function handleRateChange(index, rate) {
|
||||
localStorage.setItem(props.sn, rate.value);
|
||||
}
|
||||
|
||||
const { element } = toRefs(props);
|
||||
const chooseId = ref('');
|
||||
const emit = defineEmits(['update:element']);
|
||||
const saveStem = () => {
|
||||
@@ -107,11 +111,33 @@ const chooseOption = (item) => {
|
||||
<style scoped lang="scss">
|
||||
.content {
|
||||
background-color: #fff;
|
||||
|
||||
& .rate-content {
|
||||
width: 100%;
|
||||
margin-top: 12px;
|
||||
|
||||
& .rate-item {
|
||||
margin-bottom: 8px;
|
||||
padding: 11px 13px;
|
||||
border: 1px solid #f4f4f4;
|
||||
border-radius: 8px;
|
||||
background: #fafbfc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mb10 {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.mb5 {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.tips {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
color: #b8b8b8;
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -18,14 +18,24 @@
|
||||
></contenteditable>
|
||||
</template>
|
||||
<template #input>
|
||||
<div v-for="(optionItem, optionItemIndex) in element.options" :key="optionItemIndex">
|
||||
<div
|
||||
v-for="(optionItem, optionItemIndex) in element.options"
|
||||
:key="optionItemIndex"
|
||||
class="rate-content"
|
||||
>
|
||||
<div
|
||||
v-for="(item, optionIndex) in optionItem"
|
||||
:key="optionIndex"
|
||||
class="rate-item"
|
||||
@click="chooseOption(item)"
|
||||
>
|
||||
<contenteditable v-model="item.option" :active="active"></contenteditable>
|
||||
<RateCharacter :config="element.config"></RateCharacter>
|
||||
<div class="mb5">
|
||||
<contenteditable v-model="item.option" :active="active"></contenteditable>
|
||||
</div>
|
||||
<div class="mb10">
|
||||
<RateCharacter :config="element.config"></RateCharacter>
|
||||
</div>
|
||||
|
||||
<div class="tips">
|
||||
<p>{{ element.config.prompt_left }}</p>
|
||||
<p>{{ element.config.prompt_center }}</p>
|
||||
@@ -81,8 +91,29 @@ const chooseOption = (item) => {
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.mb10 {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.mb5 {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.content {
|
||||
background-color: #fff;
|
||||
|
||||
& .rate-content {
|
||||
width: 100%;
|
||||
margin-top: 12px;
|
||||
|
||||
& .rate-item {
|
||||
margin-bottom: 8px;
|
||||
padding: 11px 5px;
|
||||
border: 1px solid #f4f4f4;
|
||||
border-radius: 8px;
|
||||
background: #fafbfc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tips {
|
||||
|
||||
@@ -107,19 +107,28 @@ watch(
|
||||
<style scoped lang="scss">
|
||||
ul {
|
||||
display: flex;
|
||||
margin-bottom: 10px;
|
||||
|
||||
//margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.rate_item {
|
||||
margin: 0 3px;
|
||||
margin-top: 5px;
|
||||
padding: 0 6px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
color: #666;
|
||||
width: 21px;
|
||||
height: 21px;
|
||||
margin: 0 5px 0 0;
|
||||
border: 1px solid #979797;
|
||||
border-radius: 5px;
|
||||
|
||||
//padding: 0 6px;
|
||||
color: #000;
|
||||
|
||||
//margin-top: 5px;
|
||||
font-weight: 600;
|
||||
line-height: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.active_item {
|
||||
border-color: #70b936;
|
||||
background-color: #70b936;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
:label="element.stem"
|
||||
:required="element.config.is_required === 1"
|
||||
label-align="top"
|
||||
class="base-select"
|
||||
class="base-select contenteditable-question-title"
|
||||
>
|
||||
<template #left-icon>
|
||||
{{ index + 1 }}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="">
|
||||
<div class="mark_container">
|
||||
<!-- <van-row gutter="20">-->
|
||||
<div v-for="(item, index) in info" :key="index" class="market-item">
|
||||
<div v-for="(item, index) in info" @click="toDetail(item)" :key="index" class="market-item">
|
||||
<div class="content">
|
||||
<div class="title fw-bold fs-14">
|
||||
<div class="flex align-center">
|
||||
@@ -46,8 +46,8 @@
|
||||
import { ref, defineProps, onMounted } from 'vue';
|
||||
import { deleteTemplate } from '@/api/home/index.js';
|
||||
import { showDialog, showSuccessToast, showFailToast } from 'vant';
|
||||
// import contentSvg from './svgs/contentSvg.svg';
|
||||
// import MarketItemSvg from './svgs/MarketItemSvg.svg';
|
||||
import { useRouter } from 'vue-router';
|
||||
const router = useRouter();
|
||||
const { info } = defineProps({
|
||||
info: {
|
||||
type: Object,
|
||||
@@ -56,6 +56,14 @@ const { info } = defineProps({
|
||||
}
|
||||
});
|
||||
const userInfo = ref({ userName: '' });
|
||||
const toDetail = (item) => {
|
||||
router.push({
|
||||
path: '/create',
|
||||
query: {
|
||||
sn: item.sn
|
||||
}
|
||||
});
|
||||
};
|
||||
const deleteItem = (item) => {
|
||||
showDialog({
|
||||
title: '是否确认删除此模板?',
|
||||
|
||||
@@ -1,83 +1,114 @@
|
||||
<template>
|
||||
<div class="new-survey-container container">
|
||||
<div v-for="item in survey" :key="item" class="new-survey_item">
|
||||
<!-- 问卷详情 -->
|
||||
<div class="survey_item_info">
|
||||
<div style="position: relative">
|
||||
<div class="survey_item_info_title">
|
||||
<van-list
|
||||
v-model:loading="loading"
|
||||
:finished="finished"
|
||||
finished-text="没有更多了"
|
||||
@load="onLoad"
|
||||
>
|
||||
<div v-for="item in survey" :key="item" class="new-survey_item">
|
||||
<!-- 问卷详情 -->
|
||||
<div class="survey_item_info">
|
||||
<div style="position: relative">
|
||||
<div class="survey_item_info_title">
|
||||
<el-text>
|
||||
<b>{{ item.project_name }}</b>
|
||||
</el-text>
|
||||
<el-text>{{ item.answer_num }}份</el-text>
|
||||
</div>
|
||||
<div class="survey_item_info_status">
|
||||
<el-space spacer="|">
|
||||
<!--报名签到-->
|
||||
<div>
|
||||
<span><img src="" alt="" /></span>
|
||||
<el-text size="small">{{ item.scene_name }}</el-text>
|
||||
</div>
|
||||
<!-- 问卷来源 -->
|
||||
<div>
|
||||
<span><img src="" alt="" /></span>
|
||||
<el-text size="small">{{ item.source === 1 ? '移动端' : 'PC端' }}</el-text>
|
||||
</div>
|
||||
<!-- 问卷时间 -->
|
||||
<div>
|
||||
<span><img src="" alt="" /></span>
|
||||
<el-text size="small">{{ item.created_at }}</el-text>
|
||||
</div>
|
||||
</el-space>
|
||||
</div>
|
||||
<div class="survey_item_status">
|
||||
<img v-if="item.status === 0" src="../../assets/img/publish/edit.png" alt="" />
|
||||
<img
|
||||
v-else-if="item.status === 1"
|
||||
src="../../assets/img/publish/publish.png"
|
||||
alt=""
|
||||
/>
|
||||
<img v-else-if="item.status === 2" src="../../assets/img/publish/end.png" alt="" />
|
||||
<!-- <span class="survey_item_info_status_text">-{{ item.status_txt }}-</span>-->
|
||||
</div>
|
||||
</div>
|
||||
<!--问卷描述-->
|
||||
<div v-if="item.remarks" class="survey_item_info_desc">
|
||||
<el-text>
|
||||
<b>{{ item.project_name }}</b>
|
||||
{{ item.remarks }}
|
||||
</el-text>
|
||||
<el-text>{{ item.answer_num }}份</el-text>
|
||||
</div>
|
||||
<div class="survey_item_info_status">
|
||||
<el-space spacer="|">
|
||||
<!--报名签到-->
|
||||
<div>
|
||||
<span><img src="" alt="" /></span>
|
||||
<el-text size="small">{{ item.scene_name }}</el-text>
|
||||
</div>
|
||||
<!-- 问卷来源 -->
|
||||
<div>
|
||||
<span><img src="" alt="" /></span>
|
||||
<el-text size="small">{{ item.source === 1 ? '移动端' : 'PC端' }}</el-text>
|
||||
</div>
|
||||
<!-- 问卷时间 -->
|
||||
<div>
|
||||
<span><img src="" alt="" /></span>
|
||||
<el-text size="small">{{ item.created_at }}</el-text>
|
||||
</div>
|
||||
</el-space>
|
||||
</div>
|
||||
<div class="survey_item_status">
|
||||
<span class="survey_item_info_status_text">-{{ item.status_txt }}-</span>
|
||||
</div>
|
||||
</div>
|
||||
<!--问卷描述-->
|
||||
<div v-if="item.remarks" class="survey_item_info_desc">
|
||||
<el-text>
|
||||
{{ item.remarks }}
|
||||
</el-text>
|
||||
<!-- action 功能位置 -->
|
||||
<div class="survey_item_action">
|
||||
<!-- <el-space direction="horizontal">-->
|
||||
<div>
|
||||
<el-button @click="deleteItem(item)"> 删除</el-button>
|
||||
<el-button @click="copyItem(item)"> 复制</el-button>
|
||||
<el-button style="border: 2px solid #71b73c" @click="toPreview(item)">
|
||||
<el-text style="color: #71b73c">预览</el-text>
|
||||
</el-button>
|
||||
<el-button color="#6fb937" @click="toPublish(item)">
|
||||
<el-text style="color: white">开启投放</el-text>
|
||||
</el-button>
|
||||
</div>
|
||||
<el-dropdown placement="top-end" trigger="click" active-color="#ee0a24">
|
||||
<Io5EllipsisHorizontalSharp />
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu
|
||||
active-color="#ee0a24"
|
||||
:close-on-click-overlay="false"
|
||||
:close-on-click-outside="false"
|
||||
>
|
||||
<el-dropdown-item @click="editItem(item)">编辑</el-dropdown-item>
|
||||
<el-dropdown-item @click="saveTemplate(item)">存为模板</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
<!-- </el-space>-->
|
||||
</div>
|
||||
</div>
|
||||
<!-- action 功能位置 -->
|
||||
<div class="survey_item_action">
|
||||
<!-- <el-space direction="horizontal">-->
|
||||
<div>
|
||||
<el-button> 删除</el-button>
|
||||
<el-button> 复制</el-button>
|
||||
<el-button style="border: 2px solid #71b73c">
|
||||
<el-text style="color: #71b73c">预览</el-text>
|
||||
</el-button>
|
||||
<el-button color="#6fb937">
|
||||
<el-text style="color: white">开启投放</el-text>
|
||||
</el-button>
|
||||
</div>
|
||||
<el-dropdown placement="top-end" trigger="click" style="">
|
||||
<Io5EllipsisHorizontalSharp />
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item>编辑</el-dropdown-item>
|
||||
<el-dropdown-item>存为模板</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
<!-- </el-space>-->
|
||||
</div>
|
||||
</div>
|
||||
</van-list>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { getSurveysPage } from '@/api/home/index.js';
|
||||
import { getSurveysPage, copySurveys, deleteSurveys, saveTemplates } from '@/api/home/index.js';
|
||||
import { Io5EllipsisHorizontalSharp } from 'vue-icons-plus/io5';
|
||||
import { showDialog, showConfirmDialog, showFailToast, showSuccessToast, showToast } from 'vant';
|
||||
import { useRouter } from 'vue-router';
|
||||
const router = useRouter();
|
||||
const survey = ref([]);
|
||||
const total = ref(0);
|
||||
const loading = ref(false);
|
||||
const finished = ref(false);
|
||||
const form = ref({
|
||||
page: 1,
|
||||
page: 0,
|
||||
pageSize: 10
|
||||
});
|
||||
|
||||
const onLoad = () => {
|
||||
// 异步更新数据
|
||||
setTimeout(() => {
|
||||
form.value.page = form.value.page + 1;
|
||||
fetchSurveys();
|
||||
}, 500);
|
||||
};
|
||||
const fetchSurveys = async () => {
|
||||
const params = {
|
||||
page: form.value.page,
|
||||
@@ -86,7 +117,8 @@ const fetchSurveys = async () => {
|
||||
};
|
||||
const res = await getSurveysPage(params);
|
||||
if (res.data.code === 0) {
|
||||
survey.value = res.data.data;
|
||||
survey.value = survey.value.concat(res.data.data);
|
||||
total.value = res.data.meta.total;
|
||||
survey.value.forEach((item) => {
|
||||
const sceneName = JSON.parse(JSON.stringify(item.scene_name));
|
||||
const nameList = sceneName.split('-');
|
||||
@@ -99,19 +131,117 @@ const fetchSurveys = async () => {
|
||||
item.created_at = timeList[0];
|
||||
}
|
||||
});
|
||||
loading.value = false;
|
||||
// 数据全部加载完成
|
||||
if (survey.value.length >= total.value) {
|
||||
finished.value = true;
|
||||
}
|
||||
} else {
|
||||
// Toast()
|
||||
}
|
||||
};
|
||||
|
||||
const deleteItem = (item) => {
|
||||
showDialog({
|
||||
title: `确认删除问卷${item.project_name} ?`,
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: '#03B03C'
|
||||
})
|
||||
.then(async () => {
|
||||
const res = await deleteSurveys(item.sn);
|
||||
if (res.data.message) {
|
||||
showToast(res.data.message);
|
||||
} else {
|
||||
showToast('删除成功!');
|
||||
}
|
||||
form.value.page = 1;
|
||||
await fetchSurveys();
|
||||
})
|
||||
.catch(() => {
|
||||
if (res.data.message) {
|
||||
showToast(res.data.message);
|
||||
}
|
||||
form.value.page = 1;
|
||||
fetchSurveys();
|
||||
});
|
||||
};
|
||||
const copyItem = (item) => {
|
||||
showDialog({
|
||||
title: `确认复制问卷${item.project_name} ?`,
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: '#03B03C'
|
||||
})
|
||||
.then(async () => {
|
||||
const res = await copySurveys(item.sn);
|
||||
if (res.data.code === 200 || res.data.code === 201) {
|
||||
showSuccessToast('复制成功');
|
||||
form.value.page = 1;
|
||||
await fetchSurveys();
|
||||
} else {
|
||||
showFailToast(res.data);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
// on cancel
|
||||
});
|
||||
};
|
||||
const toPreview = (item) => {
|
||||
router.push({
|
||||
path: '/preview',
|
||||
query: {
|
||||
sn: item.sn,
|
||||
name: item.project_name,
|
||||
source: 0
|
||||
}
|
||||
});
|
||||
};
|
||||
const toPublish = (item) => {
|
||||
router.push({
|
||||
path: '/publish',
|
||||
query: {
|
||||
sn: item.sn
|
||||
}
|
||||
});
|
||||
};
|
||||
const editItem = (item) => {
|
||||
router.push({
|
||||
path: '/create',
|
||||
query: {
|
||||
sn: item.sn
|
||||
}
|
||||
});
|
||||
};
|
||||
// 保存为模板
|
||||
const saveTemplate = async (item) => {
|
||||
const data = JSON.parse(JSON.stringify(item));
|
||||
const res = await saveTemplates(item.sn, data);
|
||||
if (res.data.code === 200 || res.data.code === 201) {
|
||||
showConfirmDialog({
|
||||
message: '模板保存成功,请前往模板市场查看!',
|
||||
showCancelButton: false
|
||||
})
|
||||
.then(() => {
|
||||
form.value.page = 1;
|
||||
fetchSurveys();
|
||||
})
|
||||
.catch(() => {
|
||||
// on cancel
|
||||
});
|
||||
} else {
|
||||
showFailToast(res.data);
|
||||
}
|
||||
};
|
||||
onMounted(() => {
|
||||
fetchSurveys();
|
||||
// fetchSurveys();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '@/assets/css/base';
|
||||
@import '@/assets/css/main';
|
||||
.el-dropdown-menu__item:not(.is-disabled):focus,
|
||||
.el-dropdown-menu__item:not(.is-disabled):hover {
|
||||
background-color: #000000;
|
||||
}
|
||||
|
||||
.new-survey-container {
|
||||
min-height: calc(100vh - 100px);
|
||||
@@ -132,8 +262,8 @@ onMounted(() => {
|
||||
|
||||
.survey_item_status {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 10px;
|
||||
top: -40px;
|
||||
right: -24px;
|
||||
padding: 28px 13px 19px 7px;
|
||||
background: url('https://lanhu-oss-2537-2.lanhuapp.com/SketchPngbb370d01215f9cedc28d567c637c011047f83a99fbb5e7ac348ebd0ef0015f32')
|
||||
100% no-repeat;
|
||||
|
||||
@@ -565,7 +565,7 @@ onMounted(async () => {
|
||||
max-height: 200px;
|
||||
color: #fff;
|
||||
|
||||
::v-deep .content-title {
|
||||
:deep(.content-title) {
|
||||
overflow: auto;
|
||||
width: 230px;
|
||||
height: 30px;
|
||||
@@ -574,7 +574,7 @@ onMounted(async () => {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
::v-deep .introduction {
|
||||
:deep(.introduction) {
|
||||
overflow: auto;
|
||||
width: 230px;
|
||||
height: 45px;
|
||||
@@ -617,8 +617,8 @@ onMounted(async () => {
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .van-popup--bottom.van-popup--round {
|
||||
background-color: #f2f2f2 !important;
|
||||
:deep(.van-popup--bottom.van-popup--round) {
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
|
||||
.setting_title {
|
||||
@@ -730,20 +730,20 @@ onMounted(async () => {
|
||||
}
|
||||
|
||||
.child-group {
|
||||
& ::v-deep .van-field__label {
|
||||
& :deep(.van-field__label) {
|
||||
width: 140px;
|
||||
color: #bfbfbf;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
& ::v-deep .van-cell__title {
|
||||
& :deep(.van-cell__title) {
|
||||
width: 140px;
|
||||
color: #bfbfbf;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .van-button--plain.van-button--primary {
|
||||
:deep(.van-button--plain.van-button--primary) {
|
||||
padding: 13px 15px;
|
||||
border: 1px solid #f0f0f0;
|
||||
border-radius: 10px;
|
||||
@@ -752,7 +752,7 @@ onMounted(async () => {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
::v-deep .van-button--plain.van-button--success {
|
||||
:deep(.van-button--plain.van-button--success) {
|
||||
padding: 13px 15px;
|
||||
border: 1px solid #70b937;
|
||||
border-radius: 10px;
|
||||
|
||||
@@ -1,18 +1,5 @@
|
||||
<template>
|
||||
<van-nav-bar
|
||||
left-arrow
|
||||
style="background-color: var(--primary-color)"
|
||||
:border="false"
|
||||
class="preview-nav"
|
||||
@click-left="$route.go(-1)"
|
||||
>
|
||||
<template #left>
|
||||
<van-icon name="left-long" class-prefix="mobilefont" size="18" style="color: white" />
|
||||
</template>
|
||||
<template #title>
|
||||
<el-text style="color: white">预览</el-text>
|
||||
</template>
|
||||
</van-nav-bar>
|
||||
<layout />
|
||||
<div ref="scrollbar" class="preview-container">
|
||||
<!-- <van-nav-bar :title="getDomString(questionsData?.survey?.title)" left-arrow />-->
|
||||
|
||||
@@ -545,7 +532,7 @@ import PreviewMatrixText from '@/views/Survey/views/Preview/components/questions
|
||||
import PreviewNPS from '@/views/Survey/views/Preview/components/questions/PreviewNPS.vue';
|
||||
import msg from './js/message';
|
||||
import answerMock from '@/views/Survey/views/Preview/js/mock.js';
|
||||
|
||||
import layout from '@/layouts/index.vue';
|
||||
// const isPreview = ref(true);
|
||||
// scrollbar
|
||||
const scrollbar = useTemplateRef('scrollbar');
|
||||
@@ -688,9 +675,9 @@ async function answer(callback, callbackBeforePage) {
|
||||
question.error = translatedText.value.ThisIsARequiredQuestion;
|
||||
}
|
||||
} else if (
|
||||
answer
|
||||
&& questionType === 1
|
||||
&& Object.keys(answer).findIndex((value) => !answer[value]) !== -1
|
||||
answer &&
|
||||
questionType === 1 &&
|
||||
Object.keys(answer).findIndex((value) => !answer[value]) !== -1
|
||||
) {
|
||||
// 单选题
|
||||
isError = true;
|
||||
@@ -865,51 +852,51 @@ async function answer(callback, callbackBeforePage) {
|
||||
const { value } = answer;
|
||||
const newValue = value.replace(/\n|\r|\r\n/g, '');
|
||||
switch (config.text_type) {
|
||||
// 字母
|
||||
case 3:
|
||||
isError
|
||||
= config.include_mark === 1
|
||||
? !/^[a-zA-Z·~!@#¥%……&*()——\-+={}|《》?:“”【】、;‘’,。、`~!@#$%^&*()_\-+=<>?:"{}|,./;'\\[\]]+$/.test(
|
||||
newValue
|
||||
) || !newValue.length
|
||||
: !/^[a-zA-Z]+$/.test(newValue) || !newValue.length;
|
||||
question.error = isError ? translatedText.value.PleaseEnterEnglishLetters : '';
|
||||
break;
|
||||
// 字母
|
||||
case 3:
|
||||
isError =
|
||||
config.include_mark === 1
|
||||
? !/^[a-zA-Z·~!@#¥%……&*()——\-+={}|《》?:“”【】、;‘’,。、`~!@#$%^&*()_\-+=<>?:"{}|,./;'\\[\]]+$/.test(
|
||||
newValue
|
||||
) || !newValue.length
|
||||
: !/^[a-zA-Z]+$/.test(newValue) || !newValue.length;
|
||||
question.error = isError ? translatedText.value.PleaseEnterEnglishLetters : '';
|
||||
break;
|
||||
// 中文
|
||||
case 4:
|
||||
isError
|
||||
= config.include_mark === 1
|
||||
? !/^(?:[\u3400-\u4DB5\u4E00-\u9FEA\uFA0E\uFA0F\uFA11\uFA13\uFA14\uFA1F\uFA21\uFA23\uFA24\uFA27-\uFA29]|[\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|[·~!@#¥%……&*()——\-+={}|《》?:“”【】、;‘’,。、`~!@#$%^&*()_\-+=<>?:"{}|,./;'\\[\]])+$/.test(
|
||||
newValue
|
||||
) || !newValue.length
|
||||
: !/^(?:[\u3400-\u4DB5\u4E00-\u9FEA\uFA0E\uFA0F\uFA11\uFA13\uFA14\uFA1F\uFA21\uFA23\uFA24\uFA27-\uFA29]|[\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0])+$/.test(
|
||||
newValue
|
||||
) || !newValue.length;
|
||||
question.error = isError ? translatedText.value.PleaseEnterChineseWords : '';
|
||||
break;
|
||||
case 4:
|
||||
isError =
|
||||
config.include_mark === 1
|
||||
? !/^(?:[\u3400-\u4DB5\u4E00-\u9FEA\uFA0E\uFA0F\uFA11\uFA13\uFA14\uFA1F\uFA21\uFA23\uFA24\uFA27-\uFA29]|[\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|[·~!@#¥%……&*()——\-+={}|《》?:“”【】、;‘’,。、`~!@#$%^&*()_\-+=<>?:"{}|,./;'\\[\]])+$/.test(
|
||||
newValue
|
||||
) || !newValue.length
|
||||
: !/^(?:[\u3400-\u4DB5\u4E00-\u9FEA\uFA0E\uFA0F\uFA11\uFA13\uFA14\uFA1F\uFA21\uFA23\uFA24\uFA27-\uFA29]|[\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0])+$/.test(
|
||||
newValue
|
||||
) || !newValue.length;
|
||||
question.error = isError ? translatedText.value.PleaseEnterChineseWords : '';
|
||||
break;
|
||||
// 邮箱
|
||||
case 5:
|
||||
isError
|
||||
= !/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(
|
||||
value
|
||||
);
|
||||
question.error = isError ? translatedText.value.PleaseEnterACorrectEmail : '';
|
||||
break;
|
||||
case 5:
|
||||
isError =
|
||||
!/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(
|
||||
value
|
||||
);
|
||||
question.error = isError ? translatedText.value.PleaseEnterACorrectEmail : '';
|
||||
break;
|
||||
// 手机号
|
||||
case 6:
|
||||
isError = !/^(?:(?:\+|00)86)?1[3-9]\d{9}$/.test(value);
|
||||
question.error = isError ? translatedText.value.PleaseEnterACorrectPhone : '';
|
||||
break;
|
||||
case 6:
|
||||
isError = !/^(?:(?:\+|00)86)?1[3-9]\d{9}$/.test(value);
|
||||
question.error = isError ? translatedText.value.PleaseEnterACorrectPhone : '';
|
||||
break;
|
||||
// 身份证号
|
||||
case 7:
|
||||
isError
|
||||
= !/^[1-9]\d{5}(?:18|19|20)\d{2}(?:0[1-9]|10|11|12)(?:0[1-9]|[1-2]\d|30|31)\d{3}[\dXx]$/.test(
|
||||
value
|
||||
);
|
||||
question.error = isError ? translatedText.value.PleaseEnterACorrectID : '';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case 7:
|
||||
isError =
|
||||
!/^[1-9]\d{5}(?:18|19|20)\d{2}(?:0[1-9]|10|11|12)(?:0[1-9]|[1-2]\d|30|31)\d{3}[\dXx]$/.test(
|
||||
value
|
||||
);
|
||||
question.error = isError ? translatedText.value.PleaseEnterACorrectID : '';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!isError && value.length < config.min && ![1, 2].includes(config.text_type)) {
|
||||
isError = true;
|
||||
@@ -921,54 +908,54 @@ async function answer(callback, callbackBeforePage) {
|
||||
Object.keys(answer).forEach((key) => {
|
||||
const value = answer[key];
|
||||
switch (config.text_type) {
|
||||
// 字母
|
||||
case 3:
|
||||
if (
|
||||
!/^[a-zA-Z·~!@#¥%……&*()——\-+={}|《》?:“”【】、;‘’,。、`~!@#$%^&*()_\-+=<>?:"{}|,./;'\\[\]]+$/.test(
|
||||
value
|
||||
)
|
||||
) {
|
||||
question.error = translatedText.value.PleaseEnterEnglishLetters;
|
||||
}
|
||||
break;
|
||||
// 字母
|
||||
case 3:
|
||||
if (
|
||||
!/^[a-zA-Z·~!@#¥%……&*()——\-+={}|《》?:“”【】、;‘’,。、`~!@#$%^&*()_\-+=<>?:"{}|,./;'\\[\]]+$/.test(
|
||||
value
|
||||
)
|
||||
) {
|
||||
question.error = translatedText.value.PleaseEnterEnglishLetters;
|
||||
}
|
||||
break;
|
||||
// 中文
|
||||
case 4:
|
||||
if (
|
||||
!/^(?:[\u3400-\u4DB5\u4E00-\u9FEA\uFA0E\uFA0F\uFA11\uFA13\uFA14\uFA1F\uFA21\uFA23\uFA24\uFA27-\uFA29]|[\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|[·~!@#¥%……&*()——\-+={}|《》?:“”【】、;‘’,。、`~!@#$%^&*()_\-+=<>?:"{}|,./;'\\[\]])+$/.test(
|
||||
value
|
||||
)
|
||||
) {
|
||||
question.error = translatedText.value.PleaseEnterChineseWords;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
if (
|
||||
!/^(?:[\u3400-\u4DB5\u4E00-\u9FEA\uFA0E\uFA0F\uFA11\uFA13\uFA14\uFA1F\uFA21\uFA23\uFA24\uFA27-\uFA29]|[\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|[·~!@#¥%……&*()——\-+={}|《》?:“”【】、;‘’,。、`~!@#$%^&*()_\-+=<>?:"{}|,./;'\\[\]])+$/.test(
|
||||
value
|
||||
)
|
||||
) {
|
||||
question.error = translatedText.value.PleaseEnterChineseWords;
|
||||
}
|
||||
break;
|
||||
// 邮箱
|
||||
case 5:
|
||||
if (
|
||||
!/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(
|
||||
value
|
||||
)
|
||||
) {
|
||||
question.error = translatedText.value.PleaseEnterACorrectEmail;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
if (
|
||||
!/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(
|
||||
value
|
||||
)
|
||||
) {
|
||||
question.error = translatedText.value.PleaseEnterACorrectEmail;
|
||||
}
|
||||
break;
|
||||
// 手机号
|
||||
case 6:
|
||||
if (!/^(?:(?:\+|00)86)?1[3-9]\d{9}$/.test(value)) {
|
||||
question.error = translatedText.value.PleaseEnterACorrectPhone;
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
if (!/^(?:(?:\+|00)86)?1[3-9]\d{9}$/.test(value)) {
|
||||
question.error = translatedText.value.PleaseEnterACorrectPhone;
|
||||
}
|
||||
break;
|
||||
// 身份证号
|
||||
case 7:
|
||||
if (
|
||||
!/^[1-9]\d{5}(?:18|19|20)\d{2}(?:0[1-9]|10|11|12)(?:0[1-9]|[1-2]\d|30|31)\d{3}[\dXx]$/.test(
|
||||
value
|
||||
)
|
||||
) {
|
||||
question.error = translatedText.value.PleaseEnterACorrectID;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case 7:
|
||||
if (
|
||||
!/^[1-9]\d{5}(?:18|19|20)\d{2}(?:0[1-9]|10|11|12)(?:0[1-9]|[1-2]\d|30|31)\d{3}[\dXx]$/.test(
|
||||
value
|
||||
)
|
||||
) {
|
||||
question.error = translatedText.value.PleaseEnterACorrectID;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!question.error && value.length < config.min && ![1, 2].includes(config.text_type)) {
|
||||
question.error = translatedText.value.PleaseEnterMoreThanOneCharacters(config.min);
|
||||
@@ -1045,14 +1032,14 @@ async function answer(callback, callbackBeforePage) {
|
||||
currentQuestions.forEach((question, index) => {
|
||||
if (index >= warnStart && index < warnEnd) {
|
||||
if (repeat.repeat_type) {
|
||||
question.warning
|
||||
= translatedText.value.TheAnswerIsRepeatedMoreThanOneTimesPleaseRevise(
|
||||
question.warning =
|
||||
translatedText.value.TheAnswerIsRepeatedMoreThanOneTimesPleaseRevise(
|
||||
repeat.allow_repeat_num,
|
||||
repeat.repeat_type
|
||||
);
|
||||
} else {
|
||||
question.error
|
||||
= translatedText.value.TheAnswerIsRepeatedMoreThanOneTimesPleaseRevise(
|
||||
question.error =
|
||||
translatedText.value.TheAnswerIsRepeatedMoreThanOneTimesPleaseRevise(
|
||||
repeat.allow_repeat_num,
|
||||
repeat.repeat_type
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user