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:
@@ -1,5 +1,5 @@
|
|||||||
# .env.development
|
# .env.development
|
||||||
VITE_APP_BASEURL=https://yls-api-uat.dctest.digitalyili.com/
|
VITE_APP_BASEURL=https://yls-api-uat.dctest.digitalyili.com
|
||||||
VITE_APP_ENV=development
|
VITE_APP_ENV=development
|
||||||
VITE_APP_CURRENTMODE=dev
|
VITE_APP_CURRENTMODE=dev
|
||||||
VITE_APP_BASEOSS=https://diaoyan-files.automark.cc
|
VITE_APP_BASEOSS=https://diaoyan-files.automark.cc
|
||||||
|
|||||||
2
.env.uat
2
.env.uat
@@ -1,5 +1,5 @@
|
|||||||
# .env.development
|
# .env.development
|
||||||
VITE_APP_BASEURL=https://yls-api-uat.dctest.digitalyili.com/api/
|
VITE_APP_BASEURL=https://yls-api-uat.dctest.digitalyili.com
|
||||||
VITE_APP_ENV=uat
|
VITE_APP_ENV=uat
|
||||||
VITE_APP_CURRENTMODE=uat
|
VITE_APP_CURRENTMODE=uat
|
||||||
VITE_APP_BASEOSS=https://diaoyan-files.automark.cc
|
VITE_APP_BASEOSS=https://diaoyan-files.automark.cc
|
||||||
|
|||||||
3
components.d.ts
vendored
3
components.d.ts
vendored
@@ -11,7 +11,6 @@ declare module 'vue' {
|
|||||||
RichText: typeof import('./src/components/RichText.vue')['default']
|
RichText: typeof import('./src/components/RichText.vue')['default']
|
||||||
RouterLink: typeof import('vue-router')['RouterLink']
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
RouterView: typeof import('vue-router')['RouterView']
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
'Van-': typeof import('vant/es')['-']
|
|
||||||
VanActionSheet: typeof import('vant/es')['ActionSheet']
|
VanActionSheet: typeof import('vant/es')['ActionSheet']
|
||||||
VanButton: typeof import('vant/es')['Button']
|
VanButton: typeof import('vant/es')['Button']
|
||||||
VanCell: typeof import('vant/es')['Cell']
|
VanCell: typeof import('vant/es')['Cell']
|
||||||
@@ -20,6 +19,7 @@ declare module 'vue' {
|
|||||||
VanCheckboxGroup: typeof import('vant/es')['CheckboxGroup']
|
VanCheckboxGroup: typeof import('vant/es')['CheckboxGroup']
|
||||||
VanCol: typeof import('vant/es')['Col']
|
VanCol: typeof import('vant/es')['Col']
|
||||||
VanDivider: typeof import('vant/es')['Divider']
|
VanDivider: typeof import('vant/es')['Divider']
|
||||||
|
VanFeild: typeof import('vant/es')['Feild']
|
||||||
VanField: typeof import('vant/es')['Field']
|
VanField: typeof import('vant/es')['Field']
|
||||||
VanGrid: typeof import('vant/es')['Grid']
|
VanGrid: typeof import('vant/es')['Grid']
|
||||||
VanGridItem: typeof import('vant/es')['GridItem']
|
VanGridItem: typeof import('vant/es')['GridItem']
|
||||||
@@ -35,6 +35,7 @@ declare module 'vue' {
|
|||||||
VanSwitch: typeof import('vant/es')['Switch']
|
VanSwitch: typeof import('vant/es')['Switch']
|
||||||
VanTabbar: typeof import('vant/es')['Tabbar']
|
VanTabbar: typeof import('vant/es')['Tabbar']
|
||||||
VanTabbarItem: typeof import('vant/es')['TabbarItem']
|
VanTabbarItem: typeof import('vant/es')['TabbarItem']
|
||||||
|
YLCascader: typeof import('./src/components/YLCascader.vue')['default']
|
||||||
YLPicker: typeof import('./src/components/YLPicker.vue')['default']
|
YLPicker: typeof import('./src/components/YLPicker.vue')['default']
|
||||||
YLSelect: typeof import('./src/components/YLSelect.vue')['default']
|
YLSelect: typeof import('./src/components/YLSelect.vue')['default']
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,9 @@
|
|||||||
"lint": "npx eslint -c ./node_modules/@yl/yili-fe-lint-config/eslintrc.vue3.js \"src/**/*.{js,ts,tsx,vue,html}\" --fix",
|
"lint": "npx eslint -c ./node_modules/@yl/yili-fe-lint-config/eslintrc.vue3.js \"src/**/*.{js,ts,tsx,vue,html}\" --fix",
|
||||||
"stylelint": "npx stylelint -c ./node_modules/@yl/yili-fe-lint-config/stylelintrc.js \"**/*.{css,scss,sass,less,vue,html}\" --fix"
|
"stylelint": "npx stylelint -c ./node_modules/@yl/yili-fe-lint-config/stylelintrc.js \"**/*.{css,scss,sass,less,vue,html}\" --fix"
|
||||||
},
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@rollup/rollup-linux-x64-musl": "*"
|
||||||
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@element-plus/icons-vue": "^2.3.1",
|
"@element-plus/icons-vue": "^2.3.1",
|
||||||
"axios": "^1.8.2",
|
"axios": "^1.8.2",
|
||||||
|
|||||||
@@ -11,6 +11,10 @@ a,
|
|||||||
transition: 0.4s;
|
transition: 0.4s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ml10 {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
@media (hover: hover) {
|
@media (hover: hover) {
|
||||||
a:hover {
|
a:hover {
|
||||||
background-color: hsla(160deg, 100%, 37%, 0.2);
|
background-color: hsla(160deg, 100%, 37%, 0.2);
|
||||||
|
|||||||
57
src/components/YLCascader.vue
Normal file
57
src/components/YLCascader.vue
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
<script setup>
|
||||||
|
import { ref, watch } from 'vue';
|
||||||
|
import 'element-plus/dist/index.css';
|
||||||
|
import { ElCascader } from 'element-plus';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
options: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const cascader = ref(props.modelValue);
|
||||||
|
const emit = defineEmits(['update:modelValue']);
|
||||||
|
// 直接使用 toRef 保持响应式
|
||||||
|
const selectedValue = ref(props.modelValue);
|
||||||
|
watch(
|
||||||
|
() => props.modelValue,
|
||||||
|
(newVal) => {
|
||||||
|
selectedValue.value = newVal;
|
||||||
|
cascader.value = newVal;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const changeValue = (value) => {
|
||||||
|
const hasEmpty = value.some((item) => item[0] === '0');
|
||||||
|
const propEmpty = cascader.value.some((item) => item[0] === '0');
|
||||||
|
if (hasEmpty && !propEmpty) {
|
||||||
|
emit('update:modelValue', [['0']]);
|
||||||
|
} else {
|
||||||
|
emit(
|
||||||
|
'update:modelValue',
|
||||||
|
value.filter((item) => item[0] !== '0')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<el-cascader
|
||||||
|
v-model="selectedValue"
|
||||||
|
class="yl-cascader"
|
||||||
|
style="width: 100%"
|
||||||
|
:show-all-levels="false"
|
||||||
|
:options="props.options"
|
||||||
|
:props="{ multiple: true }"
|
||||||
|
@change="changeValue"
|
||||||
|
>
|
||||||
|
</el-cascader>
|
||||||
|
</template>
|
||||||
|
<style scoped>
|
||||||
|
::v-deep .yl-cascader {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -84,7 +84,9 @@ const getType = (v: any) => {
|
|||||||
return Object.prototype.toString.call(v).slice(8, -1).toLowerCase();
|
return Object.prototype.toString.call(v).slice(8, -1).toLowerCase();
|
||||||
};
|
};
|
||||||
// 返回指定格式的日期时间
|
// 返回指定格式的日期时间
|
||||||
const getDateByFormat = (date: Date | string, fmt: dateFormat) => {
|
const getDateByFormat = (dateParam: Date | string, fmt: dateFormat) => {
|
||||||
|
// 避免直接修改参数
|
||||||
|
let date = dateParam;
|
||||||
const thisDateType = getType(date);
|
const thisDateType = getType(date);
|
||||||
if (date === '' || (thisDateType !== 'date' && thisDateType !== 'string')) {
|
if (date === '' || (thisDateType !== 'date' && thisDateType !== 'string')) {
|
||||||
date = new Date();
|
date = new Date();
|
||||||
@@ -100,7 +102,6 @@ const getDateByFormat = (date: Date | string, fmt: dateFormat) => {
|
|||||||
const m = date.getMinutes();
|
const m = date.getMinutes();
|
||||||
const s = date.getSeconds();
|
const s = date.getSeconds();
|
||||||
// 个位数补0
|
// 个位数补0
|
||||||
// 月份比实际获取的少1,所以要加1
|
|
||||||
const _M = M < 10 ? `0${M}` : M.toString();
|
const _M = M < 10 ? `0${M}` : M.toString();
|
||||||
const _D = D < 10 ? `0${D}` : D.toString();
|
const _D = D < 10 ? `0${D}` : D.toString();
|
||||||
const _h = h < 10 ? `0${h}` : h.toString();
|
const _h = h < 10 ? `0${h}` : h.toString();
|
||||||
@@ -116,13 +117,15 @@ const getDateByFormat = (date: Date | string, fmt: dateFormat) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 比较两个日期大小
|
// 比较两个日期大小
|
||||||
const dateRangeLegal = (sDate: string | Date, eDate: string | Date) => {
|
const dateRangeLegal = (sDateParam: string | Date, eDateParam: string | Date) => {
|
||||||
|
// 避免直接修改参数
|
||||||
|
let sDate = sDateParam;
|
||||||
|
let eDate = eDateParam;
|
||||||
if (!sDate || !eDate) {
|
if (!sDate || !eDate) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// 补全模板
|
// 补全模板
|
||||||
const complateStr = '0000-01-01 00:00:00';
|
const complateStr = '0000-01-01 00:00:00';
|
||||||
// 兼容ios
|
|
||||||
if (typeof sDate === 'string') {
|
if (typeof sDate === 'string') {
|
||||||
sDate = (sDate + complateStr.slice(sDate.length)).replace(/-/g, '/');
|
sDate = (sDate + complateStr.slice(sDate.length)).replace(/-/g, '/');
|
||||||
}
|
}
|
||||||
@@ -167,8 +170,8 @@ const getMaxDateLimit = computed(() => {
|
|||||||
props.format
|
props.format
|
||||||
);
|
);
|
||||||
const tempStr = '0000-12-31 23:59:59';
|
const tempStr = '0000-12-31 23:59:59';
|
||||||
const result
|
const result =
|
||||||
= props.maxDate.length !== 0 && thisMax.length > props.maxDate.length
|
props.maxDate.length !== 0 && thisMax.length > props.maxDate.length
|
||||||
? thisMax.slice(0, props.maxDate.length) + tempStr.slice(props.maxDate.length)
|
? thisMax.slice(0, props.maxDate.length) + tempStr.slice(props.maxDate.length)
|
||||||
: thisMax;
|
: thisMax;
|
||||||
return result.slice(0, props.format.length);
|
return result.slice(0, props.format.length);
|
||||||
@@ -191,8 +194,8 @@ function onChange({ selectedValues, columnIndex }) {
|
|||||||
renderMinuteColumns,
|
renderMinuteColumns,
|
||||||
renderSecondColumns
|
renderSecondColumns
|
||||||
];
|
];
|
||||||
updateColumns[columnIndex]
|
updateColumns[columnIndex] &&
|
||||||
&& updateColumns[columnIndex](changeValue, getMinDateLimit.value, getMaxDateLimit.value, false);
|
updateColumns[columnIndex](changeValue, getMinDateLimit.value, getMaxDateLimit.value, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 渲染全部列
|
// 渲染全部列
|
||||||
@@ -318,15 +321,16 @@ const renderMonthColumns = (
|
|||||||
s: string,
|
s: string,
|
||||||
e: string,
|
e: string,
|
||||||
isFirst: boolean,
|
isFirst: boolean,
|
||||||
outRange: boolean = false
|
outRangeParam: boolean = false
|
||||||
) => {
|
) => {
|
||||||
const thisY = Number(v.slice(0, 4)); // 获取当前月
|
let outRange = outRangeParam;
|
||||||
const thisM = Number(v.slice(5, 7)); // 获取当前月
|
const thisY = Number(v.slice(0, 4));
|
||||||
const minY = Number(s.slice(0, 4)); // 最小年份
|
const thisM = Number(v.slice(5, 7));
|
||||||
const maxY = Number(e.slice(0, 4)); // 最大年份
|
const minY = Number(s.slice(0, 4));
|
||||||
const listArr: any = []; // 获取月份数组
|
const maxY = Number(e.slice(0, 4));
|
||||||
let forStart = -1; // 最小月份
|
const listArr: any = [];
|
||||||
let forEnd = -1; // 最小月份
|
let forStart = -1;
|
||||||
|
let forEnd = -1;
|
||||||
if (thisY === minY && thisY === maxY) {
|
if (thisY === minY && thisY === maxY) {
|
||||||
forStart = Number(s.slice(5, 7));
|
forStart = Number(s.slice(5, 7));
|
||||||
forEnd = Number(e.slice(5, 7));
|
forEnd = Number(e.slice(5, 7));
|
||||||
@@ -389,24 +393,25 @@ const renderDayColumns = (
|
|||||||
s: string,
|
s: string,
|
||||||
e: string,
|
e: string,
|
||||||
isFirst: boolean,
|
isFirst: boolean,
|
||||||
outRange: boolean = false
|
outRangeParam: boolean = false
|
||||||
) => {
|
) => {
|
||||||
const thisYM = v.slice(0, 7); // 获取当前年月
|
let outRange = outRangeParam;
|
||||||
const thisD = Number(v.slice(8, 10)); // 获取当前日
|
const thisYM = v.slice(0, 7);
|
||||||
const startYM = s.slice(0, 7); // 开始时间临界值
|
const thisD = Number(v.slice(8, 10));
|
||||||
const endYM = e.slice(0, 7); // 结束时间临界值
|
const startYM = s.slice(0, 7);
|
||||||
const listArr: any = []; // 获取月份数组
|
const endYM = e.slice(0, 7);
|
||||||
let forStart = -1; // 最小月份
|
const listArr: any = [];
|
||||||
let forEnd = -1; // 最小月份
|
let forStart = -1;
|
||||||
|
let forEnd = -1;
|
||||||
if (thisYM === startYM && thisYM === endYM) {
|
if (thisYM === startYM && thisYM === endYM) {
|
||||||
forStart = Number(s.slice(8, 10)); // 开始时间的天临界值
|
forStart = Number(s.slice(8, 10));
|
||||||
forEnd = Number(e.slice(8, 10)); // 结束时间的天临界值
|
forEnd = Number(e.slice(8, 10));
|
||||||
} else if (thisYM === startYM) {
|
} else if (thisYM === startYM) {
|
||||||
forStart = Number(s.slice(8, 10));
|
forStart = Number(s.slice(8, 10));
|
||||||
forEnd = getCountDays(Number(v.slice(0, 4)), Number(v.slice(5, 7)));
|
forEnd = getCountDays(Number(v.slice(0, 4)), Number(v.slice(5, 7)));
|
||||||
} else if (thisYM === endYM) {
|
} else if (thisYM === endYM) {
|
||||||
forStart = 1;
|
forStart = 1;
|
||||||
forEnd = Number(e.slice(8, 10)); // 结束时间的天临界值
|
forEnd = Number(e.slice(8, 10));
|
||||||
} else {
|
} else {
|
||||||
forStart = 1;
|
forStart = 1;
|
||||||
forEnd = getCountDays(Number(v.slice(0, 4)), Number(v.slice(5, 7)));
|
forEnd = getCountDays(Number(v.slice(0, 4)), Number(v.slice(5, 7)));
|
||||||
@@ -460,18 +465,24 @@ const renderHourColumns = (
|
|||||||
s: string,
|
s: string,
|
||||||
e: string,
|
e: string,
|
||||||
isFirst: boolean,
|
isFirst: boolean,
|
||||||
outRange: boolean = false
|
outRangeParam: boolean = false
|
||||||
) => {
|
) => {
|
||||||
const thisYMD = v.slice(0, 10); // 获取当前年月日
|
// 避免直接修改参数
|
||||||
const startYMD = s.slice(0, 10); // 开始时间临界值
|
let outRange = outRangeParam;
|
||||||
const endYMD = e.slice(0, 10); // 结束时间临界值
|
// 获取当前年月日
|
||||||
const thisH = Number(v.slice(11, 13)); // 获取当前小时
|
const thisYMD = v.slice(0, 10);
|
||||||
const listArr: any = []; // 获取小时数组
|
// 开始时间临界值
|
||||||
let forStart = -1; // 最小月份
|
const startYMD = s.slice(0, 10);
|
||||||
let forEnd = -1; // 最小月份
|
// 结束时间临界值
|
||||||
|
const endYMD = e.slice(0, 10);
|
||||||
|
// 获取当前小时
|
||||||
|
const thisH = Number(v.slice(11, 13));
|
||||||
|
const listArr: any = [];
|
||||||
|
let forStart = -1;
|
||||||
|
let forEnd = -1;
|
||||||
if (thisYMD === startYMD && thisYMD === endYMD) {
|
if (thisYMD === startYMD && thisYMD === endYMD) {
|
||||||
forStart = Number(s.slice(11, 13)); // 开始时间的小时临界值
|
forStart = Number(s.slice(11, 13));
|
||||||
forEnd = Number(e.slice(11, 13)); // 结束时间的小时临界值
|
forEnd = Number(e.slice(11, 13));
|
||||||
} else if (thisYMD === startYMD) {
|
} else if (thisYMD === startYMD) {
|
||||||
forStart = Number(s.slice(11, 13));
|
forStart = Number(s.slice(11, 13));
|
||||||
forEnd = 23;
|
forEnd = 23;
|
||||||
@@ -531,15 +542,20 @@ const renderMinuteColumns = (
|
|||||||
s: string,
|
s: string,
|
||||||
e: string,
|
e: string,
|
||||||
isFirst: boolean,
|
isFirst: boolean,
|
||||||
outRange: boolean = false
|
outRangeParam: boolean = false
|
||||||
) => {
|
) => {
|
||||||
const thisYMDH = v.slice(0, 13); // 获取当前年月日小时
|
// 避免直接修改参数
|
||||||
const startYMDH = s.slice(0, 13); // 开始时间临界值
|
let outRange = outRangeParam;
|
||||||
const endYMDH = e.slice(0, 13); // 结束时间临界值
|
// 获取当前年月日小时
|
||||||
const thisM = Number(v.slice(14, 16)); // 获取当前分钟
|
const thisYMDH = v.slice(0, 13);
|
||||||
const listArr: any = []; // 获取数组
|
// 开始时间临界值
|
||||||
let forStart = -1; // 循环最小值
|
const startYMDH = s.slice(0, 13);
|
||||||
let forEnd = -1; // 循环最大值
|
// 结束时间临界值
|
||||||
|
const endYMDH = e.slice(0, 13);
|
||||||
|
const thisM = Number(v.slice(14, 16));
|
||||||
|
const listArr: any = [];
|
||||||
|
let forStart = -1;
|
||||||
|
let forEnd = -1;
|
||||||
if (thisYMDH === startYMDH && thisYMDH === endYMDH) {
|
if (thisYMDH === startYMDH && thisYMDH === endYMDH) {
|
||||||
forStart = Number(s.slice(14, 16));
|
forStart = Number(s.slice(14, 16));
|
||||||
forEnd = Number(e.slice(14, 16));
|
forEnd = Number(e.slice(14, 16));
|
||||||
@@ -602,15 +618,16 @@ const renderSecondColumns = (
|
|||||||
s: string,
|
s: string,
|
||||||
e: string,
|
e: string,
|
||||||
isFirst: boolean,
|
isFirst: boolean,
|
||||||
outRange: boolean = false
|
outRangeParam: boolean = false
|
||||||
) => {
|
) => {
|
||||||
const thisYMDHM = v.slice(0, 16); // 获取当前年月日小时
|
let outRange = outRangeParam;
|
||||||
const startYMDHM = s.slice(0, 16); // 开始时间临界值
|
const thisYMDHM = v.slice(0, 16);
|
||||||
const endYMDHM = e.slice(0, 16); // 结束时间临界值
|
const startYMDHM = s.slice(0, 16);
|
||||||
const thisS = Number(v.slice(17, 19)); // 获取当前分钟
|
const endYMDHM = e.slice(0, 16);
|
||||||
const listArr: any = []; // 获取数组
|
const thisS = Number(v.slice(17, 19));
|
||||||
let forStart = -1; // 循环最小值
|
const listArr: any = [];
|
||||||
let forEnd = -1; // 循环最大值
|
let forStart = -1;
|
||||||
|
let forEnd = -1;
|
||||||
if (thisYMDHM === startYMDHM && thisYMDHM === endYMDHM) {
|
if (thisYMDHM === startYMDHM && thisYMDHM === endYMDHM) {
|
||||||
forStart = Number(s.slice(17, 19));
|
forStart = Number(s.slice(17, 19));
|
||||||
forEnd = Number(e.slice(17, 19));
|
forEnd = Number(e.slice(17, 19));
|
||||||
@@ -665,7 +682,7 @@ watch(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
immediate: true // 立即监听--进入就会执行一次 监听显影状态
|
immediate: true
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -88,7 +88,6 @@ const checkContains = (element, target) => {
|
|||||||
try {
|
try {
|
||||||
return element?.contains(target) ?? false;
|
return element?.contains(target) ?? false;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Contains check failed:', e);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -134,11 +133,11 @@ onMounted(() => {
|
|||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
z-index: 2008;
|
z-index: 2008;
|
||||||
|
display: flex;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
display: flex;
|
|
||||||
line-height: 40px;
|
line-height: 40px;
|
||||||
|
|
||||||
& button {
|
& button {
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ import axios from 'axios';
|
|||||||
const service = axios.create({
|
const service = axios.create({
|
||||||
// baseURL: `${baseURL}`, // url = base url + request url
|
// baseURL: `${baseURL}`, // url = base url + request url
|
||||||
// withCredentials: true, // send cookies when cross-domain requests
|
// withCredentials: true, // send cookies when cross-domain requests
|
||||||
timeout: 30000 // request timeout
|
// request timeout
|
||||||
|
timeout: 30000
|
||||||
});
|
});
|
||||||
|
|
||||||
// request interceptor
|
// request interceptor
|
||||||
@@ -36,7 +37,12 @@ service.interceptors.request.use(
|
|||||||
// response interceptor
|
// response interceptor
|
||||||
service.interceptors.response.use(
|
service.interceptors.response.use(
|
||||||
(response) => {
|
(response) => {
|
||||||
if (response.status === 200 || response.status === 201 || response.status === 202 || response.status === 204) {
|
if (
|
||||||
|
response.status === 200
|
||||||
|
|| response.status === 201
|
||||||
|
|| response.status === 202
|
||||||
|
|| response.status === 204
|
||||||
|
) {
|
||||||
if (response.config.method === 'put') {
|
if (response.config.method === 'put') {
|
||||||
// message.success('保存中...');
|
// message.success('保存中...');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -407,7 +407,6 @@ export const useCommonStore = defineStore('common', {
|
|||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
async fetchQuestionInfo(questionInfo) {
|
async fetchQuestionInfo(questionInfo) {
|
||||||
console.log(questionInfo, 456);
|
|
||||||
try {
|
try {
|
||||||
if (!questionInfo) return;
|
if (!questionInfo) return;
|
||||||
|
|
||||||
|
|||||||
@@ -7,44 +7,44 @@ export default {
|
|||||||
title: '',
|
title: '',
|
||||||
options: [
|
options: [
|
||||||
[
|
[
|
||||||
{
|
// {
|
||||||
id: '',
|
// id: '',
|
||||||
is_fixed: 0,
|
// is_fixed: 0,
|
||||||
is_other: 0,
|
// is_other: 0,
|
||||||
is_remove_other: 0,
|
// is_remove_other: 0,
|
||||||
option: '<p>选项1</p>',
|
// option: '<p>选项1</p>',
|
||||||
option_config: {
|
// option_config: {
|
||||||
image_url: [],
|
// image_url: [],
|
||||||
title: '',
|
// title: '',
|
||||||
instructions: [],
|
// instructions: [],
|
||||||
option_type: 0,
|
// option_type: 0,
|
||||||
limit_right_content: ''
|
// limit_right_content: ''
|
||||||
},
|
// },
|
||||||
option_index: 1,
|
// option_index: 1,
|
||||||
parent_id: 0,
|
// parent_id: 0,
|
||||||
type: 0,
|
// type: 0,
|
||||||
cascade: [],
|
// cascade: [],
|
||||||
config: []
|
// config: []
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
id: '',
|
// id: '',
|
||||||
is_fixed: 0,
|
// is_fixed: 0,
|
||||||
is_other: 0,
|
// is_other: 0,
|
||||||
is_remove_other: 0,
|
// is_remove_other: 0,
|
||||||
option: '<p>选项2</p>',
|
// option: '<p>选项2</p>',
|
||||||
option_config: {
|
// option_config: {
|
||||||
image_url: [],
|
// image_url: [],
|
||||||
title: '',
|
// title: '',
|
||||||
instructions: [],
|
// instructions: [],
|
||||||
option_type: 0,
|
// option_type: 0,
|
||||||
limit_right_content: ''
|
// limit_right_content: ''
|
||||||
},
|
// },
|
||||||
option_index: 1,
|
// option_index: 1,
|
||||||
parent_id: 0,
|
// parent_id: 0,
|
||||||
type: 0,
|
// type: 0,
|
||||||
cascade: [],
|
// cascade: [],
|
||||||
config: []
|
// config: []
|
||||||
}
|
// }
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -12,9 +12,11 @@ const baseURL = config.default.proxyUrl;
|
|||||||
|
|
||||||
// create an axios instance
|
// create an axios instance
|
||||||
const service = axios.create({
|
const service = axios.create({
|
||||||
baseURL: `${baseURL}`, // url = base url + request url
|
// url = base url + request url
|
||||||
|
baseURL: `${baseURL}/api`,
|
||||||
// withCredentials: true, // send cookies when cross-domain requests
|
// withCredentials: true, // send cookies when cross-domain requests
|
||||||
timeout: 30000 // request timeout
|
// request timeout
|
||||||
|
timeout: 30000
|
||||||
});
|
});
|
||||||
|
|
||||||
// request interceptor
|
// request interceptor
|
||||||
@@ -24,10 +26,10 @@ service.interceptors.request.use(
|
|||||||
config.headers.Accept = 'application/json';
|
config.headers.Accept = 'application/json';
|
||||||
}
|
}
|
||||||
config.headers.Authorization = `${localStorage.getItem('plantToken')}`;
|
config.headers.Authorization = `${localStorage.getItem('plantToken')}`;
|
||||||
if (!config.headers.remoteIp) {
|
// if (!config.headers.remoteIp) {
|
||||||
config.baseURL += '/api';
|
// config.baseURL += '/api';
|
||||||
}
|
// }
|
||||||
delete config.headers.host;
|
// delete config.headers.host;
|
||||||
config.headers.remoteIp = localStorage.getItem('plantIp') || '127.0.0.1';
|
config.headers.remoteIp = localStorage.getItem('plantIp') || '127.0.0.1';
|
||||||
// if (store.state.common.token) {
|
// if (store.state.common.token) {
|
||||||
// config.headers['Login-Type'] = 'pc';
|
// config.headers['Login-Type'] = 'pc';
|
||||||
@@ -42,10 +44,10 @@ service.interceptors.request.use(
|
|||||||
service.interceptors.response.use(
|
service.interceptors.response.use(
|
||||||
(response) => {
|
(response) => {
|
||||||
if (
|
if (
|
||||||
response.status === 200
|
response.status === 200 ||
|
||||||
|| response.status === 201
|
response.status === 201 ||
|
||||||
|| response.status === 202
|
response.status === 202 ||
|
||||||
|| response.status === 204
|
response.status === 204
|
||||||
) {
|
) {
|
||||||
if (response.config.method === 'put') {
|
if (response.config.method === 'put') {
|
||||||
// message.success('保存中...');
|
// message.success('保存中...');
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
*/
|
*/
|
||||||
export function getSequenceName(names, list, options) {
|
export function getSequenceName(names, list, options) {
|
||||||
const result = [];
|
const result = [];
|
||||||
const start = options?.start ?? 1; // 从数字几开始
|
// 从数字几开始
|
||||||
|
const start = options?.start ?? 1;
|
||||||
|
|
||||||
names.forEach((name) => {
|
names.forEach((name) => {
|
||||||
const sequence = [];
|
const sequence = [];
|
||||||
@@ -61,7 +62,8 @@ export function getDomText(dom) {
|
|||||||
* @returns {boolean[]}
|
* @returns {boolean[]}
|
||||||
*/
|
*/
|
||||||
export function isRichRepeat(list, comparedList, options) {
|
export function isRichRepeat(list, comparedList, options) {
|
||||||
const imageAsDifference = options?.imageAsDifference !== false; // 不比较图片。只要存在图片,则认为两段富文本不同
|
// 不比较图片。只要存在图片,则认为两段富文本不同
|
||||||
|
const imageAsDifference = options?.imageAsDifference !== false;
|
||||||
|
|
||||||
return list.map((rich) => {
|
return list.map((rich) => {
|
||||||
return comparedList.some((compared) => {
|
return comparedList.some((compared) => {
|
||||||
@@ -83,7 +85,8 @@ export function isRichRepeat(list, comparedList, options) {
|
|||||||
* @returns {boolean[]}
|
* @returns {boolean[]}
|
||||||
*/
|
*/
|
||||||
export function isRichEmpty(list, options) {
|
export function isRichEmpty(list, options) {
|
||||||
const imageAsEmpty = options?.imageAsEmpty === true; // 不判断图片。只要存在图片,则认为两段富文本不为空
|
// 不判断图片。只要存在图片,则认为两段富文本不为空
|
||||||
|
const imageAsEmpty = options?.imageAsEmpty === true;
|
||||||
|
|
||||||
return list.map((rich) => {
|
return list.map((rich) => {
|
||||||
if (!imageAsEmpty) {
|
if (!imageAsEmpty) {
|
||||||
|
|||||||
@@ -293,7 +293,6 @@ const actionEvent = (item, el) => {
|
|||||||
const actionFun = {
|
const actionFun = {
|
||||||
// 单选事件 添加选项
|
// 单选事件 添加选项
|
||||||
radioAddOption: (element) => {
|
radioAddOption: (element) => {
|
||||||
console.log(element);
|
|
||||||
element.options.map((item) => {
|
element.options.map((item) => {
|
||||||
item.push({
|
item.push({
|
||||||
id: uuidv4(),
|
id: uuidv4(),
|
||||||
@@ -313,6 +312,8 @@ const actionFun = {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
element.last_option_index += 1;
|
element.last_option_index += 1;
|
||||||
|
|
||||||
|
saveQueItem(questionInfo.value.logics, [element]);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -320,16 +321,59 @@ const actionFun = {
|
|||||||
* @param element {import('./components/Questions/types/martrix.js').MatrixSurveyQuestion}
|
* @param element {import('./components/Questions/types/martrix.js').MatrixSurveyQuestion}
|
||||||
*/
|
*/
|
||||||
addMatrixRowOption: (element) => {
|
addMatrixRowOption: (element) => {
|
||||||
|
const optionIndex = element.last_option_index;
|
||||||
element.options[0].push({
|
element.options[0].push({
|
||||||
option: '新增行'
|
cascade: [],
|
||||||
|
config: [],
|
||||||
|
is_fixed: 0,
|
||||||
|
is_other: 0,
|
||||||
|
is_remove_other: 0,
|
||||||
|
option: `<p style="text-align:center">行标签${element.options[0].length + 1}</p>`,
|
||||||
|
option_config: {
|
||||||
|
image_url: [],
|
||||||
|
title: '',
|
||||||
|
instructions: [],
|
||||||
|
option_type: 0,
|
||||||
|
limit_right_content: '<p>右极文字1</p>'
|
||||||
|
},
|
||||||
|
parent_id: 0,
|
||||||
|
type: 1,
|
||||||
|
id: uuidv4(),
|
||||||
|
option_index: optionIndex + 1
|
||||||
});
|
});
|
||||||
|
|
||||||
|
element.last_option_index = optionIndex + 1;
|
||||||
|
|
||||||
|
saveQueItem(questionInfo.value.logics, [element]);
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* martrix 矩阵列数增加
|
* martrix 矩阵列数增加
|
||||||
* @param element {import('./components/Questions/types/martrix.js').MatrixSurveyQuestion}
|
* @param element {import('./components/Questions/types/martrix.js').MatrixSurveyQuestion}
|
||||||
*/
|
*/
|
||||||
addMatrixColumnOption: (element) => {
|
addMatrixColumnOption: (element) => {
|
||||||
element.options[1].push({ option: '新增列' });
|
const optionIndex = element.last_option_index;
|
||||||
|
element.options[1].push({
|
||||||
|
cascade: [],
|
||||||
|
config: [],
|
||||||
|
is_fixed: 0,
|
||||||
|
is_other: 0,
|
||||||
|
is_remove_other: 0,
|
||||||
|
option: `<p style="text-align:center">列标签${element.options[1].length + 1}</p>`,
|
||||||
|
option_config: {
|
||||||
|
image_url: [],
|
||||||
|
title: '',
|
||||||
|
instructions: [],
|
||||||
|
option_type: 0,
|
||||||
|
limit_right_content: '<p>右极文字1</p>'
|
||||||
|
},
|
||||||
|
parent_id: 0,
|
||||||
|
type: 2,
|
||||||
|
id: uuidv4(),
|
||||||
|
option_index: optionIndex + 1
|
||||||
|
});
|
||||||
|
|
||||||
|
element.last_option_index = optionIndex + 1;
|
||||||
|
saveQueItem(questionInfo.value.logics, [element]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,7 @@
|
|||||||
></van-switch>
|
></van-switch>
|
||||||
</template>
|
</template>
|
||||||
</van-cell>
|
</van-cell>
|
||||||
|
|
||||||
<van-divider></van-divider>
|
<van-divider></van-divider>
|
||||||
<van-cell title="题前隐藏" :border="false" @click="questionSetting('before')">
|
<van-cell title="题前隐藏" :border="false" @click="questionSetting('before')">
|
||||||
<template #right-icon>
|
<template #right-icon>
|
||||||
@@ -69,13 +70,25 @@
|
|||||||
:config="activeQuestion.config"
|
:config="activeQuestion.config"
|
||||||
@update-config="updateConfig"
|
@update-config="updateConfig"
|
||||||
></rate-question-action>
|
></rate-question-action>
|
||||||
|
|
||||||
<!-- 填空-->
|
<!-- 填空-->
|
||||||
<completion-question-action
|
<completion-question-action
|
||||||
v-if="activeQuestion.question_type === 4"
|
v-if="[4, 8].includes(activeQuestion.question_type)"
|
||||||
v-model="activeQuestion"
|
v-model="activeQuestion"
|
||||||
@save-option="saveSettings"
|
@save-option="saveSettings"
|
||||||
></completion-question-action>
|
></completion-question-action>
|
||||||
|
|
||||||
|
<field-upload-question-action
|
||||||
|
v-if="activeQuestion.question_type === 18"
|
||||||
|
v-model="activeQuestion"
|
||||||
|
@save-option="saveSettings"
|
||||||
|
></field-upload-question-action>
|
||||||
|
|
||||||
|
<!-- 矩阵题目-->
|
||||||
|
<martrix-question-action
|
||||||
|
v-if="[8, 9, 10].includes(activeQuestion.question_type)"
|
||||||
|
v-model="activeQuestion"
|
||||||
|
@save-option="saveSettings"
|
||||||
|
></martrix-question-action>
|
||||||
</van-cell-group>
|
</van-cell-group>
|
||||||
</van-action-sheet>
|
</van-action-sheet>
|
||||||
<!-- 移动 复制-->
|
<!-- 移动 复制-->
|
||||||
@@ -125,6 +138,8 @@ import { storeToRefs } from 'pinia';
|
|||||||
import QuestionBefore from '@/views/Design/components/ActionCompoents/components/QuestionItemAction/QuestionBefore.vue';
|
import QuestionBefore from '@/views/Design/components/ActionCompoents/components/QuestionItemAction/QuestionBefore.vue';
|
||||||
import RateQuestionAction from './components/QuestionItemAction/RateQuestionAction.vue';
|
import RateQuestionAction from './components/QuestionItemAction/RateQuestionAction.vue';
|
||||||
import CompletionQuestionAction from '@/views/Design/components/ActionCompoents/components/QuestionItemAction/CompletionQuestionAction.vue';
|
import CompletionQuestionAction from '@/views/Design/components/ActionCompoents/components/QuestionItemAction/CompletionQuestionAction.vue';
|
||||||
|
import FieldUploadQuestionAction from '@/views/Design/components/ActionCompoents/components/QuestionItemAction/FieldUploadQuestionAction.vue';
|
||||||
|
import MartrixQuestionAction from '@/views/Design/components/ActionCompoents/components/QuestionItemAction/MartrixQuestionAction.vue';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
const store = useCounterStore();
|
const store = useCounterStore();
|
||||||
const { questionsInfo } = storeToRefs(store);
|
const { questionsInfo } = storeToRefs(store);
|
||||||
@@ -238,8 +253,8 @@ const getSkipTypeText = (skipType) => {
|
|||||||
const ls = [];
|
const ls = [];
|
||||||
logics.map((item) => {
|
logics.map((item) => {
|
||||||
if (
|
if (
|
||||||
item.skip_type === skipType
|
item.skip_type === skipType &&
|
||||||
&& item.question_index === activeQuestion.value.question_index
|
item.question_index === activeQuestion.value.question_index
|
||||||
) {
|
) {
|
||||||
ls.push(item);
|
ls.push(item);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import request from '@/utils/request.js';
|
||||||
|
|
||||||
|
export function getFileType() {
|
||||||
|
return request({
|
||||||
|
url: `/console/file_type`,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -68,7 +68,6 @@
|
|||||||
</template>
|
</template>
|
||||||
</van-field>
|
</van-field>
|
||||||
</van-cell-group>
|
</van-cell-group>
|
||||||
<van-divider></van-divider>
|
|
||||||
|
|
||||||
<van-cell
|
<van-cell
|
||||||
v-if="![5, 6, 7].includes(actionQuestion.config.text_type)"
|
v-if="![5, 6, 7].includes(actionQuestion.config.text_type)"
|
||||||
|
|||||||
@@ -0,0 +1,182 @@
|
|||||||
|
<template>
|
||||||
|
<van-cell title="文件数量" :border="false" label-align="left"> </van-cell>
|
||||||
|
<van-field
|
||||||
|
v-model="actionQuestion.config.min_number"
|
||||||
|
label="最少"
|
||||||
|
type="number"
|
||||||
|
:border="false"
|
||||||
|
label-align="left"
|
||||||
|
input-align="right"
|
||||||
|
class="action-field"
|
||||||
|
placeholder="不限"
|
||||||
|
@blur="emit('saveOption')"
|
||||||
|
@update:model-value="
|
||||||
|
(value) => {
|
||||||
|
actionQuestion.config.min_number = Number(value);
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<template #right-icon>
|
||||||
|
<span>个</span>
|
||||||
|
</template>
|
||||||
|
</van-field>
|
||||||
|
<van-field
|
||||||
|
v-model="actionQuestion.config.max_number"
|
||||||
|
label="最多"
|
||||||
|
type="number"
|
||||||
|
:border="false"
|
||||||
|
placeholder="不限"
|
||||||
|
input-align="right"
|
||||||
|
class="action-field"
|
||||||
|
@blur="emit('saveOption')"
|
||||||
|
@update:model-value="
|
||||||
|
(value) => {
|
||||||
|
actionQuestion.config.max_number = Number(value);
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<template #right-icon>
|
||||||
|
<span>个</span>
|
||||||
|
</template>
|
||||||
|
</van-field>
|
||||||
|
<van-divider></van-divider>
|
||||||
|
<van-cell title="文件大小" :border="false" label-align="left"> </van-cell>
|
||||||
|
<van-field
|
||||||
|
v-model="actionQuestion.config.min_size"
|
||||||
|
label="最少"
|
||||||
|
type="number"
|
||||||
|
:border="false"
|
||||||
|
label-align="left"
|
||||||
|
input-align="right"
|
||||||
|
class="action-field"
|
||||||
|
placeholder="不限"
|
||||||
|
@blur="emit('saveOption')"
|
||||||
|
@update:model-value="
|
||||||
|
(value) => {
|
||||||
|
actionQuestion.config.min_size = Number(value);
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<template #right-icon>
|
||||||
|
<span>M</span>
|
||||||
|
</template>
|
||||||
|
</van-field>
|
||||||
|
<van-field
|
||||||
|
v-model="actionQuestion.config.max_size"
|
||||||
|
label="最多"
|
||||||
|
type="number"
|
||||||
|
:border="false"
|
||||||
|
placeholder="不限"
|
||||||
|
input-align="right"
|
||||||
|
class="action-field"
|
||||||
|
@blur="emit('saveOption')"
|
||||||
|
@update:model-value="
|
||||||
|
(value) => {
|
||||||
|
actionQuestion.config.max_size = Number(value);
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<template #right-icon>
|
||||||
|
<span>M</span>
|
||||||
|
</template>
|
||||||
|
</van-field>
|
||||||
|
|
||||||
|
<van-divider></van-divider>
|
||||||
|
<van-field label="文件格式" :border="false" label-align="top">
|
||||||
|
<template #input>
|
||||||
|
<div style="width: 100%">
|
||||||
|
<YLCascader
|
||||||
|
v-if="fileTypeList.length > 0"
|
||||||
|
v-model="fileType"
|
||||||
|
:options="fileTypeList"
|
||||||
|
@update:model-value="changeFileType"
|
||||||
|
></YLCascader>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</van-field>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { computed, defineEmits, onMounted, ref } from 'vue';
|
||||||
|
import YLCascader from '@/components/YLCascader.vue';
|
||||||
|
|
||||||
|
import { getFileType } from './Api/Index.js';
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:modelValue', 'saveOption']);
|
||||||
|
const actionQuestion = computed({
|
||||||
|
get() {
|
||||||
|
return props.modelValue;
|
||||||
|
},
|
||||||
|
set(newValue) {
|
||||||
|
emit('update:modelValue', newValue);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const fileTypeList = ref([]);
|
||||||
|
const fileType = ref([]);
|
||||||
|
actionQuestion.value.config.file_type.split(',').map((item) => {
|
||||||
|
const type = item.split('-');
|
||||||
|
fileType.value.push(type);
|
||||||
|
});
|
||||||
|
const getFileTypeList = () => {
|
||||||
|
getFileType().then((res) => {
|
||||||
|
if (res.data) {
|
||||||
|
// 对象keymap
|
||||||
|
fileTypeList.value = Object.keys(res.data.data).map((key) => {
|
||||||
|
return {
|
||||||
|
label: key,
|
||||||
|
value: key,
|
||||||
|
children: res.data.data[key].map((item) => {
|
||||||
|
return {
|
||||||
|
label: item,
|
||||||
|
value: item
|
||||||
|
};
|
||||||
|
})
|
||||||
|
};
|
||||||
|
});
|
||||||
|
fileTypeList.value.unshift({
|
||||||
|
label: '不限',
|
||||||
|
value: '0',
|
||||||
|
isUnlimitSelected: 1,
|
||||||
|
children: null
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const changeFileType = (value) => {
|
||||||
|
if (value === [['0']]) {
|
||||||
|
actionQuestion.value.config.file_type = '0';
|
||||||
|
emit('saveOption');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const ls = [];
|
||||||
|
value.map((item) => {
|
||||||
|
const obj = [];
|
||||||
|
item.map((s) => {
|
||||||
|
obj.push(s);
|
||||||
|
});
|
||||||
|
ls.push(obj.join('-'));
|
||||||
|
});
|
||||||
|
actionQuestion.value.config.file_type = ls.join(',');
|
||||||
|
emit('saveOption');
|
||||||
|
};
|
||||||
|
onMounted(() => {
|
||||||
|
getFileTypeList();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.action-field {
|
||||||
|
& ::v-deep .van-field__label {
|
||||||
|
color: #bfbfbf;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,156 @@
|
|||||||
|
<template>
|
||||||
|
<van-cell v-if="[9, 10].includes(actionQuestion.question_type)" title="选项随机" :border="false">
|
||||||
|
<template #right-icon>
|
||||||
|
<van-switch
|
||||||
|
v-model="actionQuestion.config.select_random"
|
||||||
|
class="option-action-sheet-switch"
|
||||||
|
size="0.5rem"
|
||||||
|
:active-value="1"
|
||||||
|
:inactive-value="0"
|
||||||
|
@change="emit('saveOption')"
|
||||||
|
></van-switch>
|
||||||
|
</template>
|
||||||
|
</van-cell>
|
||||||
|
<van-field
|
||||||
|
v-if="
|
||||||
|
[9, 10].includes(actionQuestion.question_type) && actionQuestion.config.select_random === 1
|
||||||
|
"
|
||||||
|
v-model="actionQuestion.config.min_select"
|
||||||
|
label=""
|
||||||
|
:border="false"
|
||||||
|
label-align="left"
|
||||||
|
input-align="right"
|
||||||
|
class="action-field"
|
||||||
|
placeholder="不限"
|
||||||
|
@blur="emit('saveOption')"
|
||||||
|
@update:model-value="
|
||||||
|
(value) => {
|
||||||
|
actionQuestion.config.min_select = Number(value);
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<template #input>
|
||||||
|
<div class="flex">
|
||||||
|
<van-checkbox
|
||||||
|
v-model="actionQuestion.config.row_random"
|
||||||
|
shape="square"
|
||||||
|
name="actionQuestion.config.row_random"
|
||||||
|
icon-size="0.5rem"
|
||||||
|
@change="emit('saveOption')"
|
||||||
|
>
|
||||||
|
行随机
|
||||||
|
</van-checkbox>
|
||||||
|
<van-checkbox
|
||||||
|
v-model="actionQuestion.config.cell_random"
|
||||||
|
class="ml10"
|
||||||
|
shape="square"
|
||||||
|
icon-size="0.5rem"
|
||||||
|
name="actionQuestion.config.cell_random"
|
||||||
|
@change="emit('saveOption')"
|
||||||
|
>
|
||||||
|
列随机
|
||||||
|
</van-checkbox>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</van-field>
|
||||||
|
<van-cell
|
||||||
|
title="右极文字"
|
||||||
|
type="number"
|
||||||
|
:border="false"
|
||||||
|
label-align="left"
|
||||||
|
input-align="right"
|
||||||
|
label-width="8em"
|
||||||
|
placeholder="不限"
|
||||||
|
readonly
|
||||||
|
@blur="emit('saveOption')"
|
||||||
|
>
|
||||||
|
<template #right-icon>
|
||||||
|
<van-switch
|
||||||
|
v-model="actionQuestion.config.is_limit_right_content"
|
||||||
|
:active-value="1"
|
||||||
|
:inactive-value="0"
|
||||||
|
size="0.5rem"
|
||||||
|
@change="emit('saveOption')"
|
||||||
|
></van-switch>
|
||||||
|
</template>
|
||||||
|
</van-cell>
|
||||||
|
<!-- 每行可选数量-->
|
||||||
|
<van-cell
|
||||||
|
v-if="[10].includes(actionQuestion.question_type)"
|
||||||
|
title="每行可选数量"
|
||||||
|
:border="false"
|
||||||
|
label-align="left"
|
||||||
|
>
|
||||||
|
</van-cell>
|
||||||
|
<van-cell-group v-if="[10].includes(actionQuestion.question_type)">
|
||||||
|
<van-field
|
||||||
|
v-model="actionQuestion.config.min_select"
|
||||||
|
label="最少"
|
||||||
|
type="number"
|
||||||
|
:border="false"
|
||||||
|
label-align="left"
|
||||||
|
input-align="right"
|
||||||
|
class="action-field"
|
||||||
|
placeholder="不限"
|
||||||
|
@blur="emit('saveOption')"
|
||||||
|
@update:model-value="
|
||||||
|
(value) => {
|
||||||
|
actionQuestion.config.min_select = Number(value);
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<template #right-icon>
|
||||||
|
<span>个</span>
|
||||||
|
</template>
|
||||||
|
</van-field>
|
||||||
|
<van-field
|
||||||
|
v-model="actionQuestion.config.max_select"
|
||||||
|
label="最多"
|
||||||
|
type="number"
|
||||||
|
:border="false"
|
||||||
|
placeholder="不限"
|
||||||
|
input-align="right"
|
||||||
|
class="action-field"
|
||||||
|
@blur="emit('saveOption')"
|
||||||
|
@update:model-value="
|
||||||
|
(value) => {
|
||||||
|
actionQuestion.config.max_select = Number(value);
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<template #right-icon>
|
||||||
|
<span>个</span>
|
||||||
|
</template>
|
||||||
|
</van-field>
|
||||||
|
</van-cell-group>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { computed, defineEmits } from 'vue';
|
||||||
|
import { saveQuestion } from '@/api/design/index.js';
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:modelValue', 'saveOption']);
|
||||||
|
const actionQuestion = computed({
|
||||||
|
get() {
|
||||||
|
return props.modelValue;
|
||||||
|
},
|
||||||
|
set(newValue) {
|
||||||
|
emit('update:modelValue', newValue);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.action-field {
|
||||||
|
& ::v-deep .van-field__label {
|
||||||
|
color: #bfbfbf;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -183,7 +183,6 @@ skipOption.push(
|
|||||||
let optionOptions = [];
|
let optionOptions = [];
|
||||||
// todo 不同题型逻辑对应不同 需要开发
|
// todo 不同题型逻辑对应不同 需要开发
|
||||||
const changeQuestionIndex = (value, logicItem) => {
|
const changeQuestionIndex = (value, logicItem) => {
|
||||||
console.log(logicItem);
|
|
||||||
if (!value) {
|
if (!value) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@@ -315,10 +314,8 @@ const symbolOptions = [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
const getQuestionType = (value) => {
|
const getQuestionType = () => {
|
||||||
console.log(beforeQuesOptions);
|
// const type = beforeQuesOptions.filter((item) => item.question_index === value)[0];
|
||||||
const type = beforeQuesOptions.filter((item) => item.question_index === value)[0];
|
|
||||||
console.log(type);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const logicIf = (value, index) => {
|
const logicIf = (value, index) => {
|
||||||
|
|||||||
@@ -73,7 +73,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import OptionAction from '@/views/Design/components/ActionCompoents/OptionAction.vue';
|
import OptionAction from '@/views/Design/components/ActionCompoents/OptionAction.vue';
|
||||||
import { defineAsyncComponent, toRefs } from 'vue';
|
import { defineAsyncComponent, toRefs, ref } from 'vue';
|
||||||
|
|
||||||
const choiceValue = ref('checked');
|
const choiceValue = ref('checked');
|
||||||
const Contenteditable = defineAsyncComponent(() => import('@/components/contenteditable.vue'));
|
const Contenteditable = defineAsyncComponent(() => import('@/components/contenteditable.vue'));
|
||||||
|
|||||||
@@ -1,71 +1,89 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Toast } from 'vant';
|
import { toRefs } from 'vue';
|
||||||
|
|
||||||
const { element } = defineProps<{ element: FileUploadQuestion }>();
|
const props = defineProps<{
|
||||||
|
element: any;
|
||||||
|
index: number;
|
||||||
|
active: boolean;
|
||||||
|
}>();
|
||||||
|
const { element } = toRefs(props);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 文件大小限制
|
* 文件大小限制
|
||||||
* @property {number} max - 最大文件大小
|
* @property {number} max - 最大文件大小
|
||||||
* @property {number} min - 最小文件大小
|
* @property {number} min - 最小文件大小
|
||||||
*/
|
*/
|
||||||
const fileLimit = {
|
// const fileLimit = {
|
||||||
// 默认3MB
|
// // 默认3MB
|
||||||
max: 1024 * 1024 * 4,
|
// max: 1024 * 1024 * 4,
|
||||||
min: 0
|
// min: 0
|
||||||
};
|
// };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 上传文件
|
* 上传文件
|
||||||
* @description 上传文件
|
* @description 上传文件
|
||||||
*/
|
*/
|
||||||
function handleFileUpload() {
|
// function handleFileUpload() {
|
||||||
const fileInput = document.createElement('input');
|
// const fileInput = document.createElement('input');
|
||||||
fileInput.type = 'file';
|
// fileInput.type = 'file';
|
||||||
// fileInput.accept = '.jpg,.jpeg,.png,.gif';
|
// // fileInput.accept = '.jpg,.jpeg,.png,.gif';
|
||||||
// fileInput.multiple = true;
|
// // fileInput.multiple = true;
|
||||||
fileInput.click();
|
// fileInput.click();
|
||||||
|
//
|
||||||
|
// fileInput.addEventListener('change', handleFileChange);
|
||||||
|
//
|
||||||
|
// function handleFileChange(event: Event) {
|
||||||
|
// const files = (event.target as HTMLInputElement).files;
|
||||||
|
// if (files) {
|
||||||
|
// for (let i = 0; i < files.length; i++) {
|
||||||
|
// const file = files[i];
|
||||||
|
// // console.log(file.size);
|
||||||
|
//
|
||||||
|
// if (file.size > fileLimit.max) {
|
||||||
|
// Toast.fail(`文件太大,超过${fileLimit.max / 1024 / 1024}MB`);
|
||||||
|
// return;
|
||||||
|
// } else if (file.size < fileLimit.min) {
|
||||||
|
// Toast.fail(`文件太小,小于${fileLimit.min / 1024 / 1024}MB`);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
fileInput.addEventListener('change', handleFileChange);
|
const emit = defineEmits(['update:element']);
|
||||||
|
const emitValue = () => {
|
||||||
function handleFileChange(event: Event) {
|
emit('update:element', element.value);
|
||||||
const files = (event.target as HTMLInputElement).files;
|
};
|
||||||
if (files) {
|
|
||||||
for (let i = 0; i < files.length; i++) {
|
|
||||||
const file = files[i];
|
|
||||||
// console.log(file.size);
|
|
||||||
|
|
||||||
if (file.size > fileLimit.max) {
|
|
||||||
Toast.fail(`文件太大,超过${fileLimit.max / 1024 / 1024}MB`);
|
|
||||||
return;
|
|
||||||
} else if (file.size < fileLimit.min) {
|
|
||||||
Toast.fail(`文件太小,小于${fileLimit.min / 1024 / 1024}MB`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<van-cell-group>
|
<van-cell-group>
|
||||||
<van-cell>
|
<van-field
|
||||||
|
v-model="element.stem"
|
||||||
|
:label="element.stem"
|
||||||
|
:required="element.config.is_required === 1"
|
||||||
|
label-align="top"
|
||||||
|
>
|
||||||
|
<template #left-icon>
|
||||||
|
{{ index + 1 }}
|
||||||
|
</template>
|
||||||
<!-- 使用 title 插槽来自定义标题 -->
|
<!-- 使用 title 插槽来自定义标题 -->
|
||||||
<template #title>
|
<template #label>
|
||||||
<span>
|
<contenteditable
|
||||||
<span v-if="element?.config?.is_required">*</span>
|
v-model="element.stem"
|
||||||
<span v-html="element.title"></span>
|
:active="active"
|
||||||
<span v-html="element.stem"></span>
|
@blur="emitValue"
|
||||||
</span>
|
></contenteditable>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #label>
|
<template #input>
|
||||||
<div class="file-upload-label" @click="handleFileUpload">
|
<div class="file-upload-label">
|
||||||
<van-icon name="photo"></van-icon>
|
<van-icon name="photo"></van-icon>
|
||||||
<span>上传文件</span>
|
<span>上传文件</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</van-cell>
|
</van-field>
|
||||||
</van-cell-group>
|
</van-cell-group>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -76,5 +94,8 @@ function handleFileUpload() {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 50px;
|
height: 50px;
|
||||||
|
padding: 5px;
|
||||||
|
border: 1px solid #dfdfdf;
|
||||||
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,12 +1,17 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useTemplateRef, type Directive } from 'vue';
|
import { useTemplateRef, toRefs } from 'vue';
|
||||||
|
|
||||||
const columnLabels = useTemplateRef<HTMLElement[]>('columnLabels');
|
const columnLabels = useTemplateRef<HTMLElement[]>('columnLabels');
|
||||||
|
|
||||||
// 注意, element.options 里面的东西是数组,第一项内容是行标签内容,第二项内容是列标签内容
|
// 注意, element.options 里面的东西是数组,第一项内容是行标签内容,第二项内容是列标签内容
|
||||||
// 类型 AI 生成 切勿盲目相信,以实际为准
|
// 类型 AI 生成 切勿盲目相信,以实际为准
|
||||||
const { element } = defineProps<{ element: MatrixSurveyQuestion }>();
|
const props = defineProps<{
|
||||||
|
element: Any;
|
||||||
|
index: number;
|
||||||
|
active: boolean;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const { element } = toRefs(props);
|
||||||
/**
|
/**
|
||||||
* input 类型映射,里面自行处理逻辑返回对应类型
|
* input 类型映射,里面自行处理逻辑返回对应类型
|
||||||
* // remark: 填空内容 question_type 8
|
* // remark: 填空内容 question_type 8
|
||||||
@@ -15,7 +20,7 @@ const { element } = defineProps<{ element: MatrixSurveyQuestion }>();
|
|||||||
* @default 'radio'
|
* @default 'radio'
|
||||||
*/
|
*/
|
||||||
const tableInputTypeMapping = (/** regx?: any */) => {
|
const tableInputTypeMapping = (/** regx?: any */) => {
|
||||||
switch (element.question_type) {
|
switch (element.value.question_type) {
|
||||||
case 8:
|
case 8:
|
||||||
return 'text';
|
return 'text';
|
||||||
case 9:
|
case 9:
|
||||||
@@ -27,29 +32,29 @@ const tableInputTypeMapping = (/** regx?: any */) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
const emit = defineEmits(['update:element']);
|
||||||
* 自定义指令,用于在元素挂载后自动获取焦点
|
const emitValue = () => {
|
||||||
*/
|
emit('update:element', element.value);
|
||||||
const vFocus: Directive = {
|
|
||||||
mounted(el: HTMLInputElement) {
|
|
||||||
el.focus();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<van-cell>
|
<van-field
|
||||||
|
v-model="element.stem"
|
||||||
|
:label="element.stem"
|
||||||
|
:required="element.config.is_required === 1"
|
||||||
|
label-align="top"
|
||||||
|
>
|
||||||
|
<template #left-icon>
|
||||||
|
{{ index + 1 }}
|
||||||
|
</template>
|
||||||
<!-- 使用 title 插槽来自定义标题 -->
|
<!-- 使用 title 插槽来自定义标题 -->
|
||||||
<template #title>
|
<template #label>
|
||||||
<span>
|
<contenteditable v-model="element.stem" :active="active" @blur="emitValue"></contenteditable>
|
||||||
<span v-if="element?.config?.is_required">*</span>
|
|
||||||
<span v-html="element.title"></span>
|
|
||||||
<span v-html="element.stem"></span>
|
|
||||||
</span>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- 使用 label 插槽来自定义标题 -->
|
<!-- 使用 label 插槽来自定义标题 -->
|
||||||
<template #label>
|
<template #input>
|
||||||
<table class="martrix-table">
|
<table class="martrix-table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -57,40 +62,43 @@ const vFocus: Directive = {
|
|||||||
<th></th>
|
<th></th>
|
||||||
<!-- 第二行内容开始填充 -->
|
<!-- 第二行内容开始填充 -->
|
||||||
<td v-for="col in element.options[1]" :key="col.option" ref="columnLabels">
|
<td v-for="col in element.options[1]" :key="col.option" ref="columnLabels">
|
||||||
<!-- 编辑状态,单次点击出输入框,失焦后关闭 -->
|
<contenteditable
|
||||||
<input
|
|
||||||
v-if="col.editor"
|
|
||||||
v-model="col.option"
|
v-model="col.option"
|
||||||
v-focus
|
:active="active"
|
||||||
type="text"
|
@blur="emitValue"
|
||||||
@focusout="col.editor = false"
|
></contenteditable>
|
||||||
/>
|
|
||||||
<span v-else @click="col.editor = true" v-html="col.option"></span>
|
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="row in element.options[0]" :key="row.option">
|
<tr v-for="row in element.options[0]" :key="row.option">
|
||||||
<!-- 编辑状态,单次点击出输入框,失焦后关闭 -->
|
<!-- 编辑状态,单次点击出输入框,失焦后关闭 -->
|
||||||
<td>
|
<td>
|
||||||
<input
|
<contenteditable
|
||||||
v-if="row.editor"
|
|
||||||
v-model="row.option"
|
v-model="row.option"
|
||||||
v-focus
|
:active="active"
|
||||||
type="text"
|
@blur="emitValue"
|
||||||
@focusout="row.editor = false"
|
></contenteditable>
|
||||||
/>
|
|
||||||
<span v-else @click="row.editor = true" v-html="row.option"></span>
|
|
||||||
</td>
|
</td>
|
||||||
<td v-for="col in element.options[1]" :key="col.option">
|
<td v-for="col in element.options[1]" :key="col.option" class="td-input">
|
||||||
<!-- 编辑状态,单次点击出输入框,失焦后关闭 -->
|
<!-- 编辑状态,单次点击出输入框,失焦后关闭 -->
|
||||||
<input :id="col.option" :type="tableInputTypeMapping()" :name="row.option" />
|
<input :id="col.option" :type="tableInputTypeMapping()" :name="row.option" />
|
||||||
</td>
|
</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>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</template>
|
</template>
|
||||||
</van-cell>
|
</van-field>
|
||||||
</template>
|
</template>
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.martrix-table {
|
.martrix-table {
|
||||||
@@ -103,12 +111,31 @@ const vFocus: Directive = {
|
|||||||
padding: 8px;
|
padding: 8px;
|
||||||
border: 1px solid #ddd;
|
border: 1px solid #ddd;
|
||||||
border-width: 0 0 1px;
|
border-width: 0 0 1px;
|
||||||
text-align: left;
|
text-align: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.td-input {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
input[type='text'] {
|
input[type='text'] {
|
||||||
width: 85%;
|
width: 85%;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
outline: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type='checkbox'] {
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 5px;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type='radio'] {
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 5px;
|
||||||
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.martrix-table-action {
|
.martrix-table-action {
|
||||||
|
|||||||
@@ -52,8 +52,7 @@ const isOptionChecked = (rowIndex: number, colIndex: number): boolean => {
|
|||||||
return !!props.matrixAnswer[key];
|
return !!props.matrixAnswer[key];
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRowNameChange = (value: string) => {
|
const handleRowNameChange = () => {
|
||||||
console.log(`row change: ${value}`);
|
|
||||||
// 你可以在这里添加其他逻辑
|
// 你可以在这里添加其他逻辑
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ const columnLabels = useTemplateRef<HTMLElement[]>('columnLabels');
|
|||||||
|
|
||||||
// 注意, element.options 里面的东西是数组,第一项内容是行标签内容,第二项内容是列标签内容
|
// 注意, element.options 里面的东西是数组,第一项内容是行标签内容,第二项内容是列标签内容
|
||||||
// 类型 AI 生成 切勿盲目相信,以实际为准
|
// 类型 AI 生成 切勿盲目相信,以实际为准
|
||||||
const { element, index } = defineProps<{ element: MatrixSurveyQuestion, index: number }>();
|
const { element, index } = defineProps<{ element: MatrixSurveyQuestion; index: number }>();
|
||||||
|
|
||||||
const rowRecord = new Array(element.options[0].length);
|
const rowRecord = new Array(element.options[0].length);
|
||||||
// matrix 答案
|
// matrix 答案
|
||||||
@@ -50,7 +50,6 @@ const vFocus: Directive = {
|
|||||||
*/
|
*/
|
||||||
function handleRowNameChange(/* value: string */) {
|
function handleRowNameChange(/* value: string */) {
|
||||||
// if (!value) return;
|
// if (!value) return;
|
||||||
console.log(`row change`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -58,15 +57,14 @@ function handleRowNameChange(/* value: string */) {
|
|||||||
*/
|
*/
|
||||||
function handleColNameChange(rowOption: string, colOption: string, e: any) {
|
function handleColNameChange(rowOption: string, colOption: string, e: any) {
|
||||||
// if (!value) return;
|
// if (!value) return;
|
||||||
const col = element.options[0].findIndex(option => {
|
const col = element.options[0].findIndex((option) => {
|
||||||
return option.option === colOption;
|
return option.option === colOption;
|
||||||
});
|
});
|
||||||
|
|
||||||
const row = element.options[1].findIndex(option => {
|
const row = element.options[1].findIndex((option) => {
|
||||||
return option.option === rowOption;
|
return option.option === rowOption;
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(`${col + 1}_${row + 1}`);
|
|
||||||
// 不同的 question_type 的 matrix 问卷处理不同的结果
|
// 不同的 question_type 的 matrix 问卷处理不同的结果
|
||||||
switch (element.question_type) {
|
switch (element.question_type) {
|
||||||
case 8: {
|
case 8: {
|
||||||
@@ -120,7 +118,6 @@ function handleColNameChange(rowOption: string, colOption: string, e: any) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -145,24 +142,37 @@ function handleColNameChange(rowOption: string, colOption: string, e: any) {
|
|||||||
<td v-for="col in element.options[1]" :key="col.option" ref="columnLabels">
|
<td v-for="col in element.options[1]" :key="col.option" ref="columnLabels">
|
||||||
<!-- 编辑状态,单次点击出输入框,失焦后关闭 -->
|
<!-- 编辑状态,单次点击出输入框,失焦后关闭 -->
|
||||||
<input
|
<input
|
||||||
v-if="col.editor" v-model="col.option" v-focus type="text" @focusout="col.editor = false"
|
v-if="col.editor"
|
||||||
|
v-model="col.option"
|
||||||
|
v-focus
|
||||||
|
type="text"
|
||||||
|
@focusout="col.editor = false"
|
||||||
@click="handleRowNameChange(col.option!)"
|
@click="handleRowNameChange(col.option!)"
|
||||||
/>
|
/>
|
||||||
<span v-else @click="col.editor = true" v-html="col.option"></span>
|
<span v-else @click="col.editor = true" v-html="col.option"></span>
|
||||||
</td>
|
</td>
|
||||||
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="(row) in element.options[0]" :key="row.option">
|
<tr v-for="row in element.options[0]" :key="row.option">
|
||||||
<!-- 编辑状态,单次点击出输入框,失焦后关闭 -->
|
<!-- 编辑状态,单次点击出输入框,失焦后关闭 -->
|
||||||
<td>
|
<td>
|
||||||
<input v-if="row.editor" v-model="row.option" v-focus type="text" @focusout="row.editor = false" />
|
<input
|
||||||
|
v-if="row.editor"
|
||||||
|
v-model="row.option"
|
||||||
|
v-focus
|
||||||
|
type="text"
|
||||||
|
@focusout="row.editor = false"
|
||||||
|
/>
|
||||||
<span v-else @click="row.editor = true" v-html="row.option"></span>
|
<span v-else @click="row.editor = true" v-html="row.option"></span>
|
||||||
</td>
|
</td>
|
||||||
<td v-for="col in element.options[1]" :key="col.option">
|
<td v-for="col in element.options[1]" :key="col.option">
|
||||||
<!-- 编辑状态,单次点击出输入框,失焦后关闭 -->
|
<!-- 编辑状态,单次点击出输入框,失焦后关闭 -->
|
||||||
<input
|
<input
|
||||||
:id="col.option" :type="tableInputTypeMapping()" :name="row.option"
|
:id="col.option"
|
||||||
|
:type="tableInputTypeMapping()"
|
||||||
|
:name="row.option"
|
||||||
@change="handleColNameChange(col.option!, row.option!, $event)"
|
@change="handleColNameChange(col.option!, row.option!, $event)"
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@@ -1,5 +1,14 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, onMounted, ref, useTemplateRef } from 'vue';
|
import { computed, onMounted, ref, useTemplateRef, toRefs } from 'vue';
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
element: any;
|
||||||
|
active: boolean;
|
||||||
|
index: number;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const { element, active } = toRefs(props);
|
||||||
|
|
||||||
const signatureCanvas = useTemplateRef('signatureCanvas');
|
const signatureCanvas = useTemplateRef('signatureCanvas');
|
||||||
|
|
||||||
const canvasWidth = ref(100);
|
const canvasWidth = ref(100);
|
||||||
@@ -63,6 +72,9 @@ onMounted(() => {
|
|||||||
|
|
||||||
// 触摸开始,开始绘制适用于移动设备
|
// 触摸开始,开始绘制适用于移动设备
|
||||||
signatureCanvas.value?.addEventListener('touchstart', (e) => {
|
signatureCanvas.value?.addEventListener('touchstart', (e) => {
|
||||||
|
if (!active.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
// 防止页面滚动
|
// 防止页面滚动
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
isDrawing = true;
|
isDrawing = true;
|
||||||
@@ -150,10 +162,34 @@ const undo = () => {
|
|||||||
ctx.putImageData(imageData, 0, 0);
|
ctx.putImageData(imageData, 0, 0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:element']);
|
||||||
|
const emitValue = () => {
|
||||||
|
emit('update:element', element.value);
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<van-cell>
|
<van-cell>
|
||||||
|
<van-field
|
||||||
|
:label="element.stem"
|
||||||
|
:required="element.config.is_required === 1"
|
||||||
|
label-align="top"
|
||||||
|
:border="false"
|
||||||
|
readonly
|
||||||
|
class="base-select"
|
||||||
|
>
|
||||||
|
<template #left-icon>
|
||||||
|
{{ index + 1 }}
|
||||||
|
</template>
|
||||||
|
<template #label>
|
||||||
|
<contenteditable
|
||||||
|
v-model="element.stem"
|
||||||
|
:active="active"
|
||||||
|
@blur="emitValue"
|
||||||
|
></contenteditable>
|
||||||
|
</template>
|
||||||
|
<template #input>
|
||||||
<div class="sign-question">
|
<div class="sign-question">
|
||||||
<canvas
|
<canvas
|
||||||
ref="signatureCanvas"
|
ref="signatureCanvas"
|
||||||
@@ -169,6 +205,8 @@ const undo = () => {
|
|||||||
<span @click="saveCanvas">完成并上传</span>
|
<span @click="saveCanvas">完成并上传</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</template>
|
||||||
|
</van-field>
|
||||||
</van-cell>
|
</van-cell>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user