feat(api): 新增通用上传文件方法
- 添加 uploadFileWidthSn 和 uploadFileWidthSnForAnswer 方法用于上传文件 - 实现 getOssInfo 方法获取 OSS 信息 - 添加 cosUpload3D 和 cosUpload 方法上传文件到 COS- 实现 docuHousecosUpload 方法上传文件到阿里云和文档库 - 优化文件命名和错误处理
This commit is contained in:
13
components.d.ts
vendored
13
components.d.ts
vendored
@@ -2,15 +2,21 @@
|
||||
// @ts-nocheck
|
||||
// Generated by unplugin-vue-components
|
||||
// Read more: https://github.com/vuejs/core/pull/3399
|
||||
export {};
|
||||
export {}
|
||||
|
||||
/* prettier-ignore */
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
Contenteditable: typeof import('./src/components/contenteditable.vue')['default']
|
||||
ElButton: typeof import('element-plus/es')['ElButton']
|
||||
ElDropdown: typeof import('element-plus/es')['ElDropdown']
|
||||
ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
|
||||
ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
|
||||
ElInput: typeof import('element-plus/es')['ElInput']
|
||||
ElOption: typeof import('element-plus/es')['ElOption']
|
||||
ElSelect: typeof import('element-plus/es')['ElSelect']
|
||||
ElSpace: typeof import('element-plus/es')['ElSpace']
|
||||
ElText: typeof import('element-plus/es')['ElText']
|
||||
RichText: typeof import('./src/components/RichText.vue')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
@@ -32,8 +38,13 @@ declare module 'vue' {
|
||||
VanRadio: typeof import('vant/es')['Radio']
|
||||
VanRadioGroup: typeof import('vant/es')['RadioGroup']
|
||||
VanRow: typeof import('vant/es')['Row']
|
||||
VanSearch: typeof import('vant/es')['Search']
|
||||
VanStepper: typeof import('vant/es')['Stepper']
|
||||
VanSwitch: typeof import('vant/es')['Switch']
|
||||
VanTab: typeof import('vant/es')['Tab']
|
||||
VanTabbar: typeof import('vant/es')['Tabbar']
|
||||
VanTabbarItem: typeof import('vant/es')['TabbarItem']
|
||||
VanTabs: typeof import('vant/es')['Tabs']
|
||||
YLCascader: typeof import('./src/components/YLCascader.vue')['default']
|
||||
YLInput: typeof import('./src/components/YLInput.vue')['default']
|
||||
YLPicker: typeof import('./src/components/YLPicker.vue')['default']
|
||||
|
||||
147
src/api/common.js
Normal file
147
src/api/common.js
Normal file
@@ -0,0 +1,147 @@
|
||||
import request from '@/utils/request';
|
||||
import createCOS from '@/utils/txyunCosUpLoad.js';
|
||||
import { uploadDocumentFile } from './upload/index.js';
|
||||
import router from '../router/index';
|
||||
import { computed } from 'vue';
|
||||
import { shrinkImage } from 'shrinkpng';
|
||||
const sn = computed(() => router.currentRoute.value.query.sn || 'default');
|
||||
export default class CommonApi {
|
||||
static uploadFileWidthSn(file, sn) {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
formData.append('sn', sn || '');
|
||||
|
||||
return request({
|
||||
url: '/console/upload_file',
|
||||
method: 'post',
|
||||
data: formData
|
||||
});
|
||||
}
|
||||
static uploadFileWidthSnForAnswer(file, sn) {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
|
||||
return request({
|
||||
url: `/answer/upload_file/${sn}`,
|
||||
method: 'post',
|
||||
data: formData
|
||||
});
|
||||
}
|
||||
/** OssInfo */
|
||||
static getOssInfo() {
|
||||
return request({
|
||||
url: '/console/files/credentials'
|
||||
});
|
||||
}
|
||||
static async cosUpload3DCompress(file, quality = 20) {
|
||||
const _file = await shrinkImage(file, { quality });
|
||||
return await this.cosUpload3D(_file);
|
||||
}
|
||||
static async cosUpload3D(file, defaultName = '') {
|
||||
let name = defaultName?.replace?.(/[\s+]/g, '_') || '';
|
||||
|
||||
const getRandomFileName = () => {
|
||||
return `3D/upload/${new Date().getTime()}_${Math.floor(Math.random() * 1000)}`;
|
||||
};
|
||||
|
||||
name = name || getRandomFileName();
|
||||
const { data } = await CommonApi.getOssInfo();
|
||||
const param = {
|
||||
region: data.Region,
|
||||
host: data.Host,
|
||||
sessionToken: data.sessionToken,
|
||||
tmpSecretId: data.tmpSecretId,
|
||||
tmpSecretKey: data.tmpSecretKey,
|
||||
bucket: data.Bucket,
|
||||
startTime: data.startTime,
|
||||
expiredTime: data.expiredTime,
|
||||
name: `${data.prefix}/${name}`,
|
||||
file
|
||||
};
|
||||
|
||||
try {
|
||||
const location = await createCOS(param);
|
||||
return {
|
||||
url: `https://${location}`,
|
||||
name
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
url: '',
|
||||
name: ''
|
||||
};
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 上传文件
|
||||
* @param {文件file} file
|
||||
* @returns {url:"",name:'fileName'}
|
||||
*/
|
||||
static async cosUpload(file, fileName) {
|
||||
let name = fileName?.replace?.(/[\s+]/g, '_') || '';
|
||||
|
||||
const getRandomFileName = (name) => {
|
||||
return `survey/${sn.value}/${new Date().getTime()}-${Math.floor(Math.random() * 1000)}-${name}`;
|
||||
};
|
||||
/* eslint-disable no-useless-escape */
|
||||
const reg = /\\|\/|\?|\?|\*|"|“|”|'|‘|’|<|>|{|}|\[|\]|\【|\】|:|:|、|\^|\$|!|~|`|\s|\+/g;
|
||||
name =
|
||||
name ||
|
||||
getRandomFileName(file?.name?.replace(reg, '') ?? '' ?? `${new Date().getTime()}.png`);
|
||||
const res = await CommonApi.getOssInfo();
|
||||
/* eslint-enable no-useless-escape */
|
||||
|
||||
const { data } = res.data;
|
||||
const param = {
|
||||
region: data.Region,
|
||||
host: data.Host,
|
||||
sessionToken: data.sessionToken,
|
||||
tmpSecretId: data.tmpSecretId,
|
||||
tmpSecretKey: data.tmpSecretKey,
|
||||
bucket: data.Bucket,
|
||||
startTime: data.startTime,
|
||||
expiredTime: data.expiredTime,
|
||||
name: `${data.prefix}/${name}`,
|
||||
file
|
||||
};
|
||||
try {
|
||||
const location = await createCOS(param);
|
||||
return {
|
||||
url: `https://${location}`,
|
||||
name
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
url: '',
|
||||
name: ''
|
||||
};
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 上传文件到阿里云和文档库
|
||||
* @param {文件file} file
|
||||
* @param {问卷id} sn
|
||||
* @param {1=问卷设计,2=数据分析,3=问卷预览,4=数据明细,5=图表分析,6=高级分析,7=市场模拟} importType
|
||||
* @returns {url:"",name:'fileName'}
|
||||
*/
|
||||
static async docuHousecosUpload(file, sn, importType, startFileName = 'survey') {
|
||||
// eslint-disable-next-line standard/no-callback-literal
|
||||
const reg = /\\|\/|\?|?|\*|"|“|”|'|‘|’|<|>|{|}|\[|\]|【|】|:|:|、|\^|\$|!|~|`|\s|\+/g;
|
||||
|
||||
// eslint-disable-next-line standard/no-callback-literal
|
||||
const fileName = `${startFileName}/${new Date().getTime()}_${Math.floor(Math.random() * 1000)}_${
|
||||
file?.name?.replace(reg, '') ?? '' ?? `${new Date().getTime()}.png`
|
||||
}`;
|
||||
try {
|
||||
const result = await this.cosUpload(file, fileName);
|
||||
uploadDocumentFile({
|
||||
url: JSON.stringify([{ name: file.name, url: result.url, size: file.size }]),
|
||||
parent_sn: sn?.value || sn,
|
||||
import_type: importType || 1
|
||||
});
|
||||
return result;
|
||||
} catch (error) {
|
||||
// error
|
||||
}
|
||||
}
|
||||
}
|
||||
8
src/api/upload/index.js
Normal file
8
src/api/upload/index.js
Normal file
@@ -0,0 +1,8 @@
|
||||
import request from '@/utils/request.js';
|
||||
export function uploadDocumentFile(data) {
|
||||
return request({
|
||||
url: `/console/document_import`,
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
<template>
|
||||
<div class="flex contenteditable align-center space-between" :class="className">
|
||||
<p
|
||||
:id="'editor' + id"
|
||||
ref="editor"
|
||||
:contenteditable="active"
|
||||
class="van-field contenteditable-content"
|
||||
@focus="onFocus"
|
||||
v-html="modelValue"
|
||||
></p>
|
||||
<div class="right-icon ml10">
|
||||
@@ -13,13 +15,15 @@
|
||||
|
||||
<div v-if="showAction && active" ref="editorAction" class="editor-action">
|
||||
<button v-for="item in actions" :key="item.name" @click="funEvent(item, $event)">
|
||||
{{ item.label }}
|
||||
<van-icon class-prefix="mobilefont" :name="item.icon"></van-icon>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { defineEmits, ref, onMounted, watch } from 'vue';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import CommonApi from '@/api/common.js';
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
@@ -36,6 +40,8 @@ const props = defineProps({
|
||||
}
|
||||
});
|
||||
|
||||
const id = ref(uuidv4());
|
||||
|
||||
const editor = ref(null);
|
||||
const editorAction = ref(null);
|
||||
const emit = defineEmits(['update:modelValue', 'blur']);
|
||||
@@ -43,8 +49,9 @@ const save = (e) => {
|
||||
emit('update:modelValue', e.innerHTML);
|
||||
};
|
||||
|
||||
const savedRange = ref(null);
|
||||
|
||||
const functions = {
|
||||
// todo 点击按钮之后 如何判断 才能让按钮再次点击 不消失 获取重新聚焦 再次选中文本?
|
||||
boldModern: () => {
|
||||
document.execCommand('bold', true, null);
|
||||
},
|
||||
@@ -53,13 +60,45 @@ const functions = {
|
||||
},
|
||||
italic: () => {
|
||||
document.execCommand('italic', false, null);
|
||||
},
|
||||
|
||||
uploadImage: async() => {
|
||||
// 保存当前光标位置
|
||||
savedRange.value = saveSelection();
|
||||
|
||||
const fileInput = document.createElement('input');
|
||||
fileInput.type = 'file';
|
||||
|
||||
fileInput.click();
|
||||
|
||||
fileInput.onchange = async(e) => {
|
||||
const [file] = e.target.files;
|
||||
if (!file) return;
|
||||
if (file.size > 2 * 1024 * 1024) {
|
||||
console.error('文件大小不能超过2M');
|
||||
return;
|
||||
}
|
||||
|
||||
const data = await CommonApi.cosUpload(file);
|
||||
const img = document.createElement('img');
|
||||
img.src = data.url;
|
||||
img.onload = () => {
|
||||
const scale = img.naturalHeight / 50;
|
||||
const width = (img.naturalWidth / scale).toFixed(0);
|
||||
const height = 50;
|
||||
const maxWidth = img.naturalWidth;
|
||||
const maxHeight = img.naturalHeight;
|
||||
const style = `style="width:${width}px;height:${height}px;max-width:${maxWidth}px;max-height:${maxHeight}px"`;
|
||||
insertImageAtCaret(`<img src=${data.url} ${style}/>`);
|
||||
|
||||
// 恢复光标位置
|
||||
restoreSelection(savedRange.value);
|
||||
};
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const funEvent = (item) => {
|
||||
// 保持焦点在编辑器
|
||||
const selection = window.getSelection();
|
||||
selection.getRangeAt(0);
|
||||
functions[item.fun]();
|
||||
};
|
||||
|
||||
@@ -82,21 +121,22 @@ const actions = [
|
||||
{
|
||||
label: '加粗',
|
||||
fun: 'boldModern',
|
||||
icon: ''
|
||||
icon: 'jiacu'
|
||||
},
|
||||
{
|
||||
label: '下划线',
|
||||
fun: 'underLine',
|
||||
icon: ''
|
||||
icon: 'xiahuaxian'
|
||||
},
|
||||
{
|
||||
label: '图片上传',
|
||||
fun: 'uploadImage',
|
||||
icon: ''
|
||||
icon: 'tupian'
|
||||
},
|
||||
{
|
||||
label: '倾斜',
|
||||
fun: 'italic'
|
||||
fun: 'italic',
|
||||
icon: 'qingxie'
|
||||
}
|
||||
];
|
||||
const checkContains = (element, target) => {
|
||||
@@ -112,8 +152,6 @@ onMounted(() => {
|
||||
showAction.value = true;
|
||||
});
|
||||
|
||||
// 如果点击了 editor 与 editorAction 其他地方就触发保存
|
||||
|
||||
document.addEventListener('click', (e) => {
|
||||
if (!editor.value || !editorAction.value) return;
|
||||
|
||||
@@ -127,19 +165,58 @@ onMounted(() => {
|
||||
emit('blur', editor.value);
|
||||
}
|
||||
});
|
||||
// editor.value.addEventListener('blur', () => {
|
||||
// setTimeout(() => {
|
||||
// showAction.value = false;
|
||||
// });
|
||||
// });
|
||||
|
||||
document.addEventListener('resize', () => {
|
||||
showAction.value = false;
|
||||
});
|
||||
});
|
||||
|
||||
// onBeforeUnmount(() => {
|
||||
// editor.value.removeEventListener('resize', handleResize);
|
||||
// });
|
||||
const onFocus = (e) => {
|
||||
// 阻止
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
console.log('Editor focused');
|
||||
};
|
||||
|
||||
// 保存当前光标位置
|
||||
const saveSelection = () => {
|
||||
const selection = window.getSelection();
|
||||
if (selection.rangeCount === 0) return null;
|
||||
|
||||
return selection.getRangeAt(0);
|
||||
};
|
||||
|
||||
// 恢复光标位置
|
||||
const restoreSelection = (range) => {
|
||||
if (!range) return;
|
||||
|
||||
const selection = window.getSelection();
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
};
|
||||
|
||||
// 在光标位置插入图片
|
||||
const insertImageAtCaret = (html) => {
|
||||
const selection = window.getSelection();
|
||||
if (selection.rangeCount === 0) return;
|
||||
|
||||
const range = selection.getRangeAt(0);
|
||||
range.deleteContents();
|
||||
|
||||
const div = document.createElement('div');
|
||||
div.innerHTML = html;
|
||||
const frag = document.createDocumentFragment();
|
||||
for (let child = div.firstChild; child; child = div.firstChild) {
|
||||
frag.appendChild(child);
|
||||
}
|
||||
|
||||
range.insertNode(frag);
|
||||
range.setStartAfter(frag);
|
||||
range.collapse(true);
|
||||
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@@ -166,7 +243,12 @@ onMounted(() => {
|
||||
& button {
|
||||
border: none;
|
||||
background: #fff;
|
||||
color: #000;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
button + button {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
|
||||
src:
|
||||
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix')
|
||||
format('embedded-opentype'),
|
||||
format('embedded-opentype'),
|
||||
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
|
||||
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
|
||||
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont')
|
||||
format('svg');
|
||||
format('svg');
|
||||
}
|
||||
|
||||
.logo {
|
||||
|
||||
@@ -14,6 +14,22 @@
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.mobilefont-jiacu::before {
|
||||
content: '\e71d';
|
||||
}
|
||||
|
||||
.mobilefont-qingxie::before {
|
||||
content: '\e71e';
|
||||
}
|
||||
|
||||
.mobilefont-xiahuaxian::before {
|
||||
content: '\e720';
|
||||
}
|
||||
|
||||
.mobilefont-tupian::before {
|
||||
content: '\e730';
|
||||
}
|
||||
|
||||
.mobilefont-del1::before {
|
||||
content: '\e637';
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -25,7 +25,7 @@ export const QUESTION_TYPE = {
|
||||
MATRIX_RADIO: 9,
|
||||
|
||||
contains(item) {
|
||||
return Object.keys(this).some((key) => this[key] == item);
|
||||
return Object.keys(this).some((key) => this[key] === item);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -368,39 +368,39 @@ export function isCross(range1, range2) {
|
||||
const isSibling = isLeft || isRight;
|
||||
|
||||
// 逻辑包含循环
|
||||
const contain =
|
||||
(isPlainSequence &&
|
||||
(((isNullish(start2) || isSequence(judge, start2, start1)) &&
|
||||
(isNullish(end2) || isSequence(judge, end2, start1))) ||
|
||||
((isNullish(start2) || isSequence(start1, start2, end1)) &&
|
||||
(isNullish(end2) || isSequence(start1, end2, end1))))) ||
|
||||
(!isPlainSequence &&
|
||||
(judge < start1
|
||||
? ((isNullish(start2) || isSequence(judge, start2, start1)) &&
|
||||
(isNullish(end2) || isSequence(judge, end2, start1))) ||
|
||||
((isNullish(start2) || isSequence(start1, start2, end1)) &&
|
||||
(isNullish(end2) || isSequence(start1, end2, end1)))
|
||||
: ((isNullish(start2) || isSequence(start1, start2, judge)) &&
|
||||
(isNullish(end2) || isSequence(start1, end2, judge))) ||
|
||||
((isNullish(start2) || isSequence(judge, start2, end1)) &&
|
||||
(isNullish(end2) || isSequence(judge, end2, end1)))));
|
||||
const contain
|
||||
= (isPlainSequence
|
||||
&& (((isNullish(start2) || isSequence(judge, start2, start1))
|
||||
&& (isNullish(end2) || isSequence(judge, end2, start1)))
|
||||
|| ((isNullish(start2) || isSequence(start1, start2, end1))
|
||||
&& (isNullish(end2) || isSequence(start1, end2, end1)))))
|
||||
|| (!isPlainSequence
|
||||
&& (judge < start1
|
||||
? ((isNullish(start2) || isSequence(judge, start2, start1))
|
||||
&& (isNullish(end2) || isSequence(judge, end2, start1)))
|
||||
|| ((isNullish(start2) || isSequence(start1, start2, end1))
|
||||
&& (isNullish(end2) || isSequence(start1, end2, end1)))
|
||||
: ((isNullish(start2) || isSequence(start1, start2, judge))
|
||||
&& (isNullish(end2) || isSequence(start1, end2, judge)))
|
||||
|| ((isNullish(start2) || isSequence(judge, start2, end1))
|
||||
&& (isNullish(end2) || isSequence(judge, end2, end1)))));
|
||||
// 循环存在封闭区间,并且循环包含逻辑
|
||||
const contained =
|
||||
!isNullish(start2) &&
|
||||
!isNullish(end2) &&
|
||||
const contained
|
||||
= !isNullish(start2)
|
||||
&& !isNullish(end2)
|
||||
// [judge, start1, end1];
|
||||
((isPlainSequence && start2 <= judge && end1 <= end2) ||
|
||||
&& ((isPlainSequence && start2 <= judge && end1 <= end2)
|
||||
// [judge, start1, end1];
|
||||
// [start1, judge, end1];
|
||||
(!isPlainSequence && start2 <= start1 && start2 <= judge && end1 <= end2));
|
||||
|| (!isPlainSequence && start2 <= start1 && start2 <= judge && end1 <= end2));
|
||||
// 循环不存在封闭区间
|
||||
const unCircled =
|
||||
(!isNullish(start2) &&
|
||||
isNullish(end2) &&
|
||||
((isPlainSequence && start2 === judge) || (!isPlainSequence && judge < start1)
|
||||
const unCircled
|
||||
= (!isNullish(start2)
|
||||
&& isNullish(end2)
|
||||
&& ((isPlainSequence && start2 === judge) || (!isPlainSequence && judge < start1)
|
||||
? start2 === judge
|
||||
: start2 === start1)) ||
|
||||
(isNullish(start2) && !isNullish(end2) && end2 === end1);
|
||||
: start2 === start1))
|
||||
|| (isNullish(start2) && !isNullish(end2) && end2 === end1);
|
||||
|
||||
return !(isSibling || contain || contained || unCircled);
|
||||
}
|
||||
@@ -420,13 +420,13 @@ function isSequence(s1, s2, s3, equal) {
|
||||
* @param store
|
||||
*/
|
||||
export function updateNewQuestionsByLoopingEffect(quesSaveParam, store) {
|
||||
const { questionInfoBeforeModified = {}, questionInfo = {} } =
|
||||
JSON.parse(JSON.stringify(store.state.common)) || {};
|
||||
const { questionInfoBeforeModified = {}, questionInfo = {} }
|
||||
= JSON.parse(JSON.stringify(store.state.common)) || {};
|
||||
|
||||
const oldPages = questionInfoBeforeModified.survey.pages;
|
||||
const newQuestions = questionInfo.questions;
|
||||
const newPages = questionInfo.survey.is_one_page_one_question
|
||||
? questionInfo.questions.filter((i) => i.question_index).map((i, idx) => [i.question_index])
|
||||
? questionInfo.questions.filter((i) => i.question_index).map((i) => [i.question_index])
|
||||
: questionInfo.survey.pages;
|
||||
const cycles = questionInfo.cycle_pages || [];
|
||||
|
||||
|
||||
@@ -33,7 +33,9 @@ function showModal(options) {
|
||||
.then(() => {
|
||||
// confirm();
|
||||
})
|
||||
.catch(() => {});
|
||||
.catch(() => {
|
||||
// catch();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,13 +43,13 @@ function showModal(options) {
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
const canPlanetPublishPSM = function (data) {
|
||||
const canPlanetPublishPSM = function(data) {
|
||||
let isFb = true;
|
||||
let message = '';
|
||||
let title = '题目设置未完成';
|
||||
const incompleteQuestionList = [];
|
||||
data.questions &&
|
||||
data.questions.forEach((s) => {
|
||||
data.questions
|
||||
&& data.questions.forEach((s) => {
|
||||
if (s.question_type === 101 && s.config.price_gradient.length <= 0) {
|
||||
isFb = false;
|
||||
message = 'psm题目未完成设置,请设置价格区间后投放';
|
||||
@@ -72,15 +74,15 @@ const canPlanetPublishPSM = function (data) {
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
const canPlanetPublishMxdAndHotArea = function (data) {
|
||||
const canPlanetPublishMxdAndHotArea = function(data) {
|
||||
let isFb = true;
|
||||
let message = '';
|
||||
const qSteams = [];
|
||||
const incompleteQuestionList = [];
|
||||
let type = 0;
|
||||
let title = '题目设置未完成';
|
||||
data.questions &&
|
||||
data.questions.forEach((s) => {
|
||||
data.questions
|
||||
&& data.questions.forEach((s) => {
|
||||
if (s.question_type === 105 && s.config.design_version <= 0) {
|
||||
isFb = false;
|
||||
message = 'maxdiff题目未完成设置,请生成设计后投放';
|
||||
@@ -119,21 +121,23 @@ const canPlanetPublishMxdAndHotArea = function (data) {
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
const canPlanetPublish3D = function (data) {
|
||||
const canPlanetPublish3D = function(data) {
|
||||
{
|
||||
let canFB = true;
|
||||
let message = '';
|
||||
const qSteams = [];
|
||||
let title = '';
|
||||
data.questions &&
|
||||
data.questions.forEach((s) => {
|
||||
data.questions
|
||||
&& data.questions.forEach((s) => {
|
||||
if (QUESTION_TYPE.contains(s.question_type)) {
|
||||
try {
|
||||
if (s.config.is_three_dimensions && !s.config.scene) {
|
||||
canFB = false;
|
||||
qSteams.push(`(${s.title})`);
|
||||
}
|
||||
} catch (error) {}
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-eval
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -154,15 +158,15 @@ const canPlanetPublish3D = function (data) {
|
||||
let message = '';
|
||||
const qSteams = [];
|
||||
let title = '';
|
||||
data.questions &&
|
||||
data.questions.forEach((s) => {
|
||||
data.questions
|
||||
&& data.questions.forEach((s) => {
|
||||
if (QUESTION_TYPE.contains(s.question_type)) {
|
||||
try {
|
||||
if (s.config.is_three_dimensions && s.config.is_binding_goods) {
|
||||
const wares = [];
|
||||
const _sceneInformation = s.config.scene_information;
|
||||
const sceneInformation =
|
||||
typeof _sceneInformation === 'string'
|
||||
const sceneInformation
|
||||
= typeof _sceneInformation === 'string'
|
||||
? JSON.parse(_sceneInformation)
|
||||
: _sceneInformation;
|
||||
sceneInformation.shelves.forEach((shelf) => {
|
||||
@@ -174,7 +178,10 @@ const canPlanetPublish3D = function (data) {
|
||||
|
||||
const options = s.options.flat();
|
||||
s.associate.forEach((ass) => {
|
||||
const question = data.questions.find((q) => q.question_index == ass.question_index);
|
||||
// eslint-disable-next-line no-eval
|
||||
const question = data.questions.find(
|
||||
(q) => q.question_index === ass.question_index
|
||||
);
|
||||
if (!question) return;
|
||||
options.push(...question.options.flat());
|
||||
});
|
||||
@@ -184,7 +191,9 @@ const canPlanetPublish3D = function (data) {
|
||||
qSteams.push(`(${s.title})`);
|
||||
}
|
||||
}
|
||||
} catch (error) {}
|
||||
} catch (error) {
|
||||
// error
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -207,14 +216,14 @@ const canPlanetPublish3D = function (data) {
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
const canPlanetPublishImage = function (data) {
|
||||
const canPlanetPublishImage = function(data) {
|
||||
{
|
||||
let canFB = true;
|
||||
let message = '';
|
||||
const qSteams = [];
|
||||
let title = '';
|
||||
data.questions &&
|
||||
data.questions.forEach((s) => {
|
||||
data.questions
|
||||
&& data.questions.forEach((s) => {
|
||||
if (s.question_type === 13) {
|
||||
try {
|
||||
if (s.options.length <= 0 || s.options.some((y) => y.length <= 0)) {
|
||||
@@ -284,9 +293,10 @@ function canPublishRandom(data, publishType) {
|
||||
const publishStr = ['', '预览', '投放'][publishType] || '投放';
|
||||
|
||||
const errors = [];
|
||||
// eslint-disable-next-line no-eval
|
||||
const randomList = data?.survey?.group_pages || [];
|
||||
|
||||
randomList.forEach((random, randomIndex) => {
|
||||
randomList.forEach((random) => {
|
||||
const list = random.list || [];
|
||||
|
||||
// 每一个随机,至少要有两个随机题组
|
||||
@@ -308,8 +318,8 @@ function canPublishRandom(data, publishType) {
|
||||
if (!isValidated) {
|
||||
errors.push({
|
||||
message:
|
||||
field.message ||
|
||||
`请填写"${random.title}"中第${index + 1}组"随机题组"的"${field.name}"`
|
||||
field.message
|
||||
|| `请填写"${random.title}"中第${index + 1}组"随机题组"的"${field.name}"`
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -369,11 +379,11 @@ function isLoopingLogicValid(data, publishType) {
|
||||
if (
|
||||
(data?.cycle_pages || []).every((i) => {
|
||||
return (
|
||||
i.question_index &&
|
||||
i.relation_type !== undefined &&
|
||||
i.relation_type !== null &&
|
||||
i.first_page &&
|
||||
i.last_page
|
||||
i.question_index
|
||||
&& i.relation_type !== undefined
|
||||
&& i.relation_type !== null
|
||||
&& i.first_page
|
||||
&& i.last_page
|
||||
);
|
||||
})
|
||||
) {
|
||||
@@ -397,7 +407,7 @@ function isLoopingLogicValid(data, publishType) {
|
||||
* @param sn
|
||||
* @param publishType undefined投放;null投放;0投放;1预览;2投放;3测试
|
||||
*/
|
||||
export const canPlanetPublish = async function (sn, publishType) {
|
||||
export const canPlanetPublish = async function(sn, publishType) {
|
||||
const parsedPublishType = !publishType ? 2 : publishType;
|
||||
const num = window.location.href.indexOf('code=');
|
||||
let code;
|
||||
|
||||
56
src/utils/txyunCosUpLoad.js
Normal file
56
src/utils/txyunCosUpLoad.js
Normal file
@@ -0,0 +1,56 @@
|
||||
// const COS = require('cos-js-sdk-v5');
|
||||
import COS from 'cos-js-sdk-v5';
|
||||
/**
|
||||
*
|
||||
* @param {腾讯云的pramas} data
|
||||
* @returns
|
||||
*/
|
||||
export default function createCOS(data) {
|
||||
const {
|
||||
bucket,
|
||||
host,
|
||||
region,
|
||||
sessionToken,
|
||||
tmpSecretId,
|
||||
tmpSecretKey,
|
||||
startTime,
|
||||
expiredTime,
|
||||
name,
|
||||
file
|
||||
} = data;
|
||||
|
||||
const config = {
|
||||
Region: region,
|
||||
Host: host,
|
||||
Bucket: bucket,
|
||||
Key: name,
|
||||
Body: file,
|
||||
onProgress: (progressData) => {
|
||||
console.log(progressData);
|
||||
}
|
||||
};
|
||||
const client = new COS({
|
||||
getAuthorization: (options, callback) => {
|
||||
// eslint-disable-next-line standard/no-callback-literal
|
||||
callback({
|
||||
TmpSecretId: tmpSecretId,
|
||||
TmpSecretKey: tmpSecretKey,
|
||||
SecurityToken: sessionToken,
|
||||
// 建议返回服务器时间作为签名的开始时间,避免用户浏览器本地时间偏差过大导致签名错误
|
||||
StartTime: startTime, // 时间戳,单位秒,如:1580000000
|
||||
ExpiredTime: expiredTime
|
||||
});
|
||||
}
|
||||
// eslint-enable standard/no-callback-literal
|
||||
});
|
||||
return new Promise((resolve, reject) => {
|
||||
client.putObject(config, (err, data) => {
|
||||
console.log('腾讯上传', err, data);
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(data.Location);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -57,9 +57,11 @@
|
||||
</template>
|
||||
</option-action>
|
||||
</van-radio-group>
|
||||
|
||||
<van-checkbox-group v-if="element.question_type === 2" v-model="value" shape="square">
|
||||
<option-action
|
||||
v-model:data="element.options[optionIndex]"
|
||||
handle=".moverQues"
|
||||
:active="active"
|
||||
:question="element"
|
||||
>
|
||||
|
||||
@@ -13,7 +13,6 @@ const signatureCanvas = useTemplateRef('signatureCanvas');
|
||||
|
||||
const canvasWidth = ref(100);
|
||||
const canvasHeight = computed(() => canvasWidth.value / 1.5);
|
||||
const showSignText = ref(true);
|
||||
const isEraser = ref(false);
|
||||
|
||||
let ctx: CanvasRenderingContext2D;
|
||||
@@ -193,7 +192,7 @@ const emitValue = () => {
|
||||
style="border: 1px dashed #ccc; border-radius: 4px"
|
||||
>
|
||||
</canvas>
|
||||
<div class="sign-text" v-if="active" :class="{ show: active }">
|
||||
<div v-if="active" class="sign-text" :class="{ show: active }">
|
||||
<span
|
||||
class="icon mobilefont mobilefont-qingkong"
|
||||
title="清空"
|
||||
@@ -207,7 +206,7 @@ const emitValue = () => {
|
||||
></span>
|
||||
<span class="icon mobilefont mobilefont-shangchuan" @click="saveCanvas"></span>
|
||||
</div>
|
||||
<div class="sign-tips" v-else>请在空白区域书写您的签名</div>
|
||||
<div v-else class="sign-tips">请在空白区域书写您的签名</div>
|
||||
</div>
|
||||
</template>
|
||||
</van-field>
|
||||
@@ -259,13 +258,14 @@ const emitValue = () => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sign-tips {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: max-content;
|
||||
transform: translate(-50%, -50%);
|
||||
color: #cdcdcd;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -97,6 +97,10 @@
|
||||
|
||||
<!-- 底部功能性按钮 -->
|
||||
<div class="survey-action">
|
||||
<!-- <div class="survey-action_setting" @click="openSettingAction">-->
|
||||
<!-- <van-icon name="setting" size="18" class="grid-icon" />-->
|
||||
<!-- <span>投放设置</span>-->
|
||||
<!-- </div>-->
|
||||
<div class="survey-action_btn">
|
||||
<van-button size="small" plain type="primary" @click="saveAs">保存</van-button>
|
||||
<van-button size="small" plain type="primary" @click="previewQuestion">预览</van-button>
|
||||
@@ -397,14 +401,14 @@ const questionEvent = (item) => {
|
||||
options:
|
||||
item.json.options.length > 0
|
||||
? item.json.options.map((item) => {
|
||||
return item.map((it) => {
|
||||
return {
|
||||
...it,
|
||||
// 主键生成
|
||||
id: uuidv4()
|
||||
};
|
||||
});
|
||||
})
|
||||
return item.map((it) => {
|
||||
return {
|
||||
...it,
|
||||
// 主键生成
|
||||
id: uuidv4()
|
||||
};
|
||||
});
|
||||
})
|
||||
: []
|
||||
})
|
||||
);
|
||||
@@ -537,7 +541,7 @@ const previewQuestion = () => {
|
||||
router.push({ name: 'preview', query: { ...route.query } });
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
onMounted(async() => {
|
||||
await getQuestionDetail();
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -4,9 +4,11 @@
|
||||
<div class="content">
|
||||
<van-cell-group v-if="status === 1" inset style="padding-top: 15px">
|
||||
<div>
|
||||
<img width="100%"
|
||||
<img
|
||||
width="100%"
|
||||
src="https://files.axshare.com/gsc/DR6075/44/1a/03/441a03a8b1004755a7a392b311acf97f/images/%E6%8A%95%E6%94%BE/u14.jpg?pageId=2f9ba10c-92b8-4c9b-b40b-04e65a0b4333"
|
||||
alt="" />
|
||||
alt=""
|
||||
/>
|
||||
</div>
|
||||
<div class="qrcode">
|
||||
<img :src="publishInfo?.img_url" alt="" width="100px" height="100px" />
|
||||
@@ -26,8 +28,13 @@
|
||||
<div v-if="status === 0 || status === 2" class="pulish-container">
|
||||
<img class="not-publish-icon" src="@/assets/img/publish/not_pulish.png" alt="" />
|
||||
<div class="text">点击"启用"按钮后,问卷才可以开始回收数据</div>
|
||||
<van-button type="primary" style="margin-top: 20px" class="publish-btn" color="#70b936"
|
||||
@click="openPublishModal">
|
||||
<van-button
|
||||
type="primary"
|
||||
style="margin-top: 20px"
|
||||
class="publish-btn"
|
||||
color="#70b936"
|
||||
@click="openPublishModal"
|
||||
>
|
||||
<template #icon>
|
||||
<i class="mobilefont icon-fabu3" style="margin-right: 6px"></i>
|
||||
</template>
|
||||
@@ -92,21 +99,21 @@ type OperateItem = (typeof operateList)[0];
|
||||
|
||||
const operateBtn = (item: OperateItem) => {
|
||||
switch (item.type) {
|
||||
case 'shareLink':
|
||||
shareLink();
|
||||
break;
|
||||
case 'copyLink':
|
||||
copyLink();
|
||||
break;
|
||||
case 'qrCode':
|
||||
downLoadImg();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case 'shareLink':
|
||||
shareLink();
|
||||
break;
|
||||
case 'copyLink':
|
||||
copyLink();
|
||||
break;
|
||||
case 'qrCode':
|
||||
downLoadImg();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
// 复制链接
|
||||
function copyLink () {
|
||||
function copyLink() {
|
||||
const input = document.createElement('input');
|
||||
input.value = publishInfo.value.url;
|
||||
document.body.appendChild(input);
|
||||
@@ -116,7 +123,7 @@ function copyLink () {
|
||||
showToast('复制成功');
|
||||
}
|
||||
// 分享链接
|
||||
function shareLink () {
|
||||
function shareLink() {
|
||||
const params = {
|
||||
type: 'shareToWx',
|
||||
title: publishInfo.value.download_url.title,
|
||||
@@ -126,11 +133,11 @@ function shareLink () {
|
||||
scene: 0 // 朋友圈1 微信好友0
|
||||
};
|
||||
console.log('shareUrl', publishInfo.value.url);
|
||||
appBridge.shareToWeChat(params, () => { });
|
||||
appBridge.shareToWeChat(params);
|
||||
}
|
||||
|
||||
// 下载二维码
|
||||
function downLoadImg () {
|
||||
function downLoadImg() {
|
||||
const { title, url } = publishInfo.value.download_url;
|
||||
if (utils.getSessionStorage('xToken')) {
|
||||
appBridge.save2Album(url, () => {
|
||||
@@ -145,7 +152,7 @@ function downLoadImg () {
|
||||
document.body.removeChild(link);
|
||||
}
|
||||
}
|
||||
async function openPublishModal () {
|
||||
async function openPublishModal() {
|
||||
const res = await canPlanetPublish(route.query.sn as string, publishType.value);
|
||||
if (res) {
|
||||
await publishSurvey({
|
||||
@@ -161,7 +168,7 @@ async function openPublishModal () {
|
||||
}
|
||||
}
|
||||
|
||||
function getCode () {
|
||||
function getCode() {
|
||||
getQrcode(sn)
|
||||
.then((res) => {
|
||||
if (res.data) {
|
||||
@@ -172,7 +179,7 @@ function getCode () {
|
||||
showFailToast(error.data?.message || error.message || '服务器错误');
|
||||
});
|
||||
}
|
||||
function fetchInfo () {
|
||||
function fetchInfo() {
|
||||
getSurveyInfo(sn)
|
||||
.then((res) => {
|
||||
status.value = Number(res.data.data.status);
|
||||
@@ -186,7 +193,7 @@ watch(status, (val) => {
|
||||
getCode();
|
||||
}
|
||||
});
|
||||
onMounted(async () => {
|
||||
onMounted(async() => {
|
||||
// status.value = 0;
|
||||
// publishInfo.value.img_url
|
||||
// = 'https://test-cxp-pubcos.yili.com/uat-yls//survey-api/publish/202503130938138261340.png';
|
||||
|
||||
Reference in New Issue
Block a user