feat(survey): 添加取消投放功能

- 在 survey/index.js 中新增 modify 函数,用于修改投放状态
- 在 Survey/Index.vue 中添加取消投放逻辑
- 优化 Publish/Index.vue 的样式
This commit is contained in:
陈昱达
2025-03-19 19:28:44 +08:00
parent c8bc7117d3
commit 9e6723b6ad
8 changed files with 151 additions and 126 deletions

View File

@@ -43,3 +43,14 @@ export function getQuestionList(params, code) {
method: 'get' method: 'get'
}); });
} }
/*取消投放*/
export function modify(params, code) {
return request({
headers: {
'survey-invite-code': code || ''
},
url: `/console/question/publish/modify`,
method: 'POST'
});
}

View File

@@ -75,7 +75,7 @@ const functions = {
document.execCommand('italic', false, null); document.execCommand('italic', false, null);
}, },
uploadImage: async () => { uploadImage: async() => {
// 保存当前光标位置 // 保存当前光标位置
savedRange.value = saveSelection(); savedRange.value = saveSelection();
@@ -84,7 +84,7 @@ const functions = {
fileInput.click(); fileInput.click();
fileInput.onchange = async (e) => { fileInput.onchange = async(e) => {
const [file] = e.target.files; const [file] = e.target.files;
if (!file) return; if (!file) return;
if (file.size > 2 * 1024 * 1024) { if (file.size > 2 * 1024 * 1024) {
@@ -146,10 +146,10 @@ const isEmptyContent = (html) => {
const trimmedHtml = html.trim(); const trimmedHtml = html.trim();
// 检查是否为空字符串、仅包含 <br> 或仅包含 <p><br></p> // 检查是否为空字符串、仅包含 <br> 或仅包含 <p><br></p>
return ( return (
trimmedHtml === '' || trimmedHtml === ''
trimmedHtml === '<br>' || || trimmedHtml === '<br>'
trimmedHtml === '<p><br></p>' || || trimmedHtml === '<p><br></p>'
trimmedHtml === '<p></p>' || trimmedHtml === '<p></p>'
); );
}; };
@@ -157,7 +157,7 @@ const onChange = (target) => {
console.log(target.innerHTML.trim(), 123); console.log(target.innerHTML.trim(), 123);
if (isEmptyContent(target.innerHTML)) { if (isEmptyContent(target.innerHTML)) {
editor.value.classList.add('editor-placeholder'); editor.value.classList.add('editor-placeholder');
//删除br // 删除br
editor.value.innerHTML = editor.value.innerHTML.replace(/<br>/g, ''); editor.value.innerHTML = editor.value.innerHTML.replace(/<br>/g, '');
} else { } else {
editor.value.classList.remove('editor-placeholder'); editor.value.classList.remove('editor-placeholder');

View File

@@ -39,7 +39,7 @@ export default {
prompt_right: '', prompt_right: '',
score_interval: 1, score_interval: 1,
score_type: 0, score_type: 0,
score_way: 0, score_way: 1, //打分类型
prompt_score: 2 prompt_score: 2
}, },
associate: [], associate: [],

View File

@@ -105,7 +105,7 @@ function handleMatrixCheckboxChange(row: number, col: number) {
// emits('update:matrixAnswer', props.matrixAnswer); // emits('update:matrixAnswer', props.matrixAnswer);
// emits('update:rowRecord', props.rowRecord); // emits('update:rowRecord', props.rowRecord);
// }; // };
const emitValue = (/*val: unknown*/) => { const emitValue = (/* val: unknown */) => {
emit('update:element', element.value); emit('update:element', element.value);
}; };
</script> </script>

View File

@@ -74,7 +74,9 @@
<el-text style="color: #71b73c">预览</el-text> <el-text style="color: #71b73c">预览</el-text>
</el-button> </el-button>
<el-button color="#6fb937" :disabled="item.source === 0" @click="toPublish(item)"> <el-button color="#6fb937" :disabled="item.source === 0" @click="toPublish(item)">
<el-text style="color: white">开启投放</el-text> <el-text style="color: white">{{
item.status === 1 ? '取消投放' : '开启投放'
}}</el-text>
</el-button> </el-button>
</div> </div>
<el-dropdown <el-dropdown
@@ -106,6 +108,7 @@
<script setup> <script setup>
import { ref, onMounted } from 'vue'; import { ref, onMounted } from 'vue';
import { getSurveysPage, copySurveys, deleteSurveys, saveTemplates } from '@/api/home/index.js'; import { getSurveysPage, copySurveys, deleteSurveys, saveTemplates } from '@/api/home/index.js';
import { modify } from '@/api/survey/index.js';
import { showDialog, showConfirmDialog, showFailToast, showSuccessToast, showToast } from 'vant'; import { showDialog, showConfirmDialog, showFailToast, showSuccessToast, showToast } from 'vant';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
const router = useRouter(); const router = useRouter();
@@ -134,7 +137,7 @@ const onLoad = () => {
fetchSurveys(); fetchSurveys();
}, 500); }, 500);
}; };
const fetchSurveys = async() => { const fetchSurveys = async () => {
const params = { const params = {
page: form.value.page, page: form.value.page,
per_page: form.value.pageSize, per_page: form.value.pageSize,
@@ -172,7 +175,7 @@ const deleteItem = (item) => {
showCancelButton: true, showCancelButton: true,
confirmButtonColor: '#03B03C' confirmButtonColor: '#03B03C'
}) })
.then(async() => { .then(async () => {
const res = await deleteSurveys(item.sn); const res = await deleteSurveys(item.sn);
if (res.data.message) { if (res.data.message) {
showToast(res.data.message); showToast(res.data.message);
@@ -196,7 +199,7 @@ const copyItem = (item) => {
showCancelButton: true, showCancelButton: true,
confirmButtonColor: '#03B03C' confirmButtonColor: '#03B03C'
}) })
.then(async() => { .then(async () => {
const res = await copySurveys(item.sn); const res = await copySurveys(item.sn);
if (res.data.code === 200 || res.data.code === 201) { if (res.data.code === 200 || res.data.code === 201) {
showSuccessToast('复制成功'); showSuccessToast('复制成功');
@@ -221,12 +224,21 @@ const toPreview = (item) => {
}); });
}; };
const toPublish = (item) => { const toPublish = (item) => {
router.push({ if (item.status === 1) {
path: '/publish', console.log(item);
query: { modify({ surveyPublishId: '' }).then((res) => {
sn: item.sn if (res.data) {
} // 吧 数据改掉
}); }
});
} else {
router.push({
path: '/publish',
query: {
sn: item.sn
}
});
}
}; };
const editItem = (item) => { const editItem = (item) => {
router.push({ router.push({
@@ -237,7 +249,7 @@ const editItem = (item) => {
}); });
}; };
// 保存为模板 // 保存为模板
const saveTemplate = async(item) => { const saveTemplate = async (item) => {
const data = JSON.parse(JSON.stringify(item)); const data = JSON.parse(JSON.stringify(item));
const res = await saveTemplates(item.sn, data); const res = await saveTemplates(item.sn, data);
if (res.data.code === 200 || res.data.code === 201) { if (res.data.code === 200 || res.data.code === 201) {

View File

@@ -7,6 +7,7 @@
v-model="questionInfo.survey.title" v-model="questionInfo.survey.title"
className="content-title" className="content-title"
:active="true" :active="true"
placeholder="请输入问卷标题"
@blur="saveTitle" @blur="saveTitle"
></contenteditable> ></contenteditable>
<!-- 问卷标注--> <!-- 问卷标注-->
@@ -14,6 +15,7 @@
v-model="questionInfo.survey.introduction" v-model="questionInfo.survey.introduction"
className="introduction" className="introduction"
:active="true" :active="true"
placeholder="请输入问卷标注"
@blur="saveTitle" @blur="saveTitle"
></contenteditable> ></contenteditable>
</div> </div>
@@ -424,14 +426,14 @@ const questionEvent = (item) => {
options: options:
item.json.options.length > 0 item.json.options.length > 0
? item.json.options.map((item) => { ? item.json.options.map((item) => {
return item.map((it) => { return item.map((it) => {
return { return {
...it, ...it,
// 主键生成 // 主键生成
id: uuidv4() id: uuidv4()
}; };
}); });
}) })
: [] : []
}) })
); );
@@ -570,7 +572,7 @@ const previewQuestion = () => {
router.push({ name: 'preview', query: { ...route.query } }); router.push({ name: 'preview', query: { ...route.query } });
}; };
onMounted(async() => { onMounted(async () => {
await getQuestionDetail(); await getQuestionDetail();
}); });
</script> </script>

View File

@@ -559,7 +559,7 @@ const {
// 第一次进入页面清空答案 // 第一次进入页面清空答案
//初始化页面到第一页 // 初始化页面到第一页
questionsData.value?.questions && clearAnswer(questionsData.value.questions); questionsData.value?.questions && clearAnswer(questionsData.value.questions);
page.value = 1; page.value = 1;
console.log(questionsData.value); console.log(questionsData.value);
@@ -683,9 +683,9 @@ async function answer(callback, callbackBeforePage) {
question.error = translatedText.value.ThisIsARequiredQuestion; question.error = translatedText.value.ThisIsARequiredQuestion;
} }
} else if ( } else if (
answer && answer
questionType === 1 && && questionType === 1
Object.keys(answer).findIndex((value) => !answer[value]) !== -1 && Object.keys(answer).findIndex((value) => !answer[value]) !== -1
) { ) {
// 单选题 // 单选题
isError = true; isError = true;
@@ -860,52 +860,52 @@ async function answer(callback, callbackBeforePage) {
const { value } = answer; const { value } = answer;
const newValue = value.replace(/\n|\r|\r\n/g, ''); const newValue = value.replace(/\n|\r|\r\n/g, '');
switch (config.text_type) { switch (config.text_type) {
// 字母 // 字母
case 3: case 3:
// eslint-disable-next-line // eslint-disable-next-line
const reg = const reg =
/^[a-zA-Z·~@#¥%…&*()—\-+={}|《》?:“”【】、;‘’,。`!$^()_<>?:",./;'\\[\]]+$/; /^[a-zA-Z·~@#¥%…&*()—\-+={}|《》?:“”【】、;‘’,。`!$^()_<>?:",./;'\\[\]]+$/;
isError = isError
config.include_mark === 1 = config.include_mark === 1
? !reg.test(newValue) || !newValue.length ? !reg.test(newValue) || !newValue.length
: !/^[a-zA-Z]+$/.test(newValue) || !newValue.length; : !/^[a-zA-Z]+$/.test(newValue) || !newValue.length;
question.error = isError ? translatedText.value.PleaseEnterEnglishLetters : ''; question.error = isError ? translatedText.value.PleaseEnterEnglishLetters : '';
break; break;
// 中文 // 中文
case 4: case 4:
isError = isError
config.include_mark === 1 = config.include_mark === 1
? !/^(?:[\u3400-\u4DB5\u4E00-\u9FEA\uFA0E\uFA0F\uFA11\uFA13\uFA14\uFA1F\uFA21\uFA23\uFA24\uFA27-\uFA29]|[\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|[a-zA-Z·~@#¥%…&*()—\-+={}|《》?:“”【】、;‘’,。`!$^()_<>?:",./;'\\[\]])+$/.test( ? !/^(?:[\u3400-\u4DB5\u4E00-\u9FEA\uFA0E\uFA0F\uFA11\uFA13\uFA14\uFA1F\uFA21\uFA23\uFA24\uFA27-\uFA29]|[\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|[a-zA-Z·~@#¥%…&*()—\-+={}|《》?:“”【】、;‘’,。`!$^()_<>?:",./;'\\[\]])+$/.test(
newValue newValue
) || !newValue.length ) || !newValue.length
: !/^(?:[\u3400-\u4DB5\u4E00-\u9FEA\uFA0E\uFA0F\uFA11\uFA13\uFA14\uFA1F\uFA21\uFA23\uFA24\uFA27-\uFA29]|[\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0])+$/.test( : !/^(?:[\u3400-\u4DB5\u4E00-\u9FEA\uFA0E\uFA0F\uFA11\uFA13\uFA14\uFA1F\uFA21\uFA23\uFA24\uFA27-\uFA29]|[\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0])+$/.test(
newValue newValue
) || !newValue.length; ) || !newValue.length;
question.error = isError ? translatedText.value.PleaseEnterChineseWords : ''; question.error = isError ? translatedText.value.PleaseEnterChineseWords : '';
break; break;
// 邮箱 // 邮箱
case 5: case 5:
isError = isError
!/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test( = !/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(
value value
); );
question.error = isError ? translatedText.value.PleaseEnterACorrectEmail : ''; question.error = isError ? translatedText.value.PleaseEnterACorrectEmail : '';
break; break;
// 手机号 // 手机号
case 6: case 6:
isError = !/^(?:(?:\+|00)86)?1[3-9]\d{9}$/.test(value); isError = !/^(?:(?:\+|00)86)?1[3-9]\d{9}$/.test(value);
question.error = isError ? translatedText.value.PleaseEnterACorrectPhone : ''; question.error = isError ? translatedText.value.PleaseEnterACorrectPhone : '';
break; break;
// 身份证号 // 身份证号
case 7: case 7:
isError = isError
!/^[1-9]\d{5}(?:18|19|20)\d{2}(?:0[1-9]|10|11|12)(?:0[1-9]|[1-2]\d|30|31)\d{3}[\dXx]$/.test( = !/^[1-9]\d{5}(?:18|19|20)\d{2}(?:0[1-9]|10|11|12)(?:0[1-9]|[1-2]\d|30|31)\d{3}[\dXx]$/.test(
value value
); );
question.error = isError ? translatedText.value.PleaseEnterACorrectID : ''; question.error = isError ? translatedText.value.PleaseEnterACorrectID : '';
break; break;
default: default:
break; break;
} }
if (!isError && value.length < config.min && ![1, 2].includes(config.text_type)) { if (!isError && value.length < config.min && ![1, 2].includes(config.text_type)) {
isError = true; isError = true;
@@ -917,54 +917,54 @@ async function answer(callback, callbackBeforePage) {
Object.keys(answer).forEach((key) => { Object.keys(answer).forEach((key) => {
const value = answer[key]; const value = answer[key];
switch (config.text_type) { switch (config.text_type) {
// 字母 // 字母
case 3: case 3:
if ( if (
!/^[a-zA-Z·~@#¥%…&*()—\-+={}|《》?:“”【】、;‘’,。`!$^()_<>?:",./;'\\[\]]+$/.test( !/^[a-zA-Z·~@#¥%…&*()—\-+={}|《》?:“”【】、;‘’,。`!$^()_<>?:",./;'\\[\]]+$/.test(
value value
) )
) { ) {
question.error = translatedText.value.PleaseEnterEnglishLetters; question.error = translatedText.value.PleaseEnterEnglishLetters;
} }
break; break;
// 中文 // 中文
case 4: case 4:
if ( if (
!/^(?:[\u3400-\u4DB5\u4E00-\u9FEA\uFA0E\uFA0F\uFA11\uFA13\uFA14\uFA1F\uFA21\uFA23\uFA24\uFA27-\uFA29]|[\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|[·~@#¥%…&*()—\-+={}|《》?:“”【】、;‘’,。`!$^()_<>?:",./;'\\[\]])+$/.test( !/^(?:[\u3400-\u4DB5\u4E00-\u9FEA\uFA0E\uFA0F\uFA11\uFA13\uFA14\uFA1F\uFA21\uFA23\uFA24\uFA27-\uFA29]|[\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|[·~@#¥%…&*()—\-+={}|《》?:“”【】、;‘’,。`!$^()_<>?:",./;'\\[\]])+$/.test(
value value
) )
) { ) {
question.error = translatedText.value.PleaseEnterChineseWords; question.error = translatedText.value.PleaseEnterChineseWords;
} }
break; break;
// 邮箱 // 邮箱
case 5: case 5:
if ( if (
!/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test( !/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(
value value
) )
) { ) {
question.error = translatedText.value.PleaseEnterACorrectEmail; question.error = translatedText.value.PleaseEnterACorrectEmail;
} }
break; break;
// 手机号 // 手机号
case 6: case 6:
if (!/^(?:(?:\+|00)86)?1[3-9]\d{9}$/.test(value)) { if (!/^(?:(?:\+|00)86)?1[3-9]\d{9}$/.test(value)) {
question.error = translatedText.value.PleaseEnterACorrectPhone; question.error = translatedText.value.PleaseEnterACorrectPhone;
} }
break; break;
// 身份证号 // 身份证号
case 7: case 7:
if ( if (
!/^[1-9]\d{5}(?:18|19|20)\d{2}(?:0[1-9]|10|11|12)(?:0[1-9]|[1-2]\d|30|31)\d{3}[\dXx]$/.test( !/^[1-9]\d{5}(?:18|19|20)\d{2}(?:0[1-9]|10|11|12)(?:0[1-9]|[1-2]\d|30|31)\d{3}[\dXx]$/.test(
value value
) )
) { ) {
question.error = translatedText.value.PleaseEnterACorrectID; question.error = translatedText.value.PleaseEnterACorrectID;
} }
break; break;
default: default:
break; break;
} }
if (!question.error && value.length < config.min && ![1, 2].includes(config.text_type)) { if (!question.error && value.length < config.min && ![1, 2].includes(config.text_type)) {
question.error = translatedText.value.PleaseEnterMoreThanOneCharacters(config.min); question.error = translatedText.value.PleaseEnterMoreThanOneCharacters(config.min);
@@ -1041,14 +1041,14 @@ async function answer(callback, callbackBeforePage) {
currentQuestions.forEach((question, index) => { currentQuestions.forEach((question, index) => {
if (index >= warnStart && index < warnEnd) { if (index >= warnStart && index < warnEnd) {
if (repeat.repeat_type) { if (repeat.repeat_type) {
question.warning = question.warning
translatedText.value.TheAnswerIsRepeatedMoreThanOneTimesPleaseRevise( = translatedText.value.TheAnswerIsRepeatedMoreThanOneTimesPleaseRevise(
repeat.allow_repeat_num, repeat.allow_repeat_num,
repeat.repeat_type repeat.repeat_type
); );
} else { } else {
question.error = question.error
translatedText.value.TheAnswerIsRepeatedMoreThanOneTimesPleaseRevise( = translatedText.value.TheAnswerIsRepeatedMoreThanOneTimesPleaseRevise(
repeat.allow_repeat_num, repeat.allow_repeat_num,
repeat.repeat_type repeat.repeat_type
); );
@@ -1395,8 +1395,8 @@ function updateAnswer(auto) {
const evt1 = {}; const evt1 = {};
if ([1].includes(question.question_type)) { if ([1].includes(question.question_type)) {
evt1.value = evt1.value
Object.keys(question.answer) = Object.keys(question.answer)
.map((key) => (question.answer[key] ? key : undefined)) .map((key) => (question.answer[key] ? key : undefined))
.filter((i) => !!i)?.[0] || undefined; .filter((i) => !!i)?.[0] || undefined;
evt1.options = question.list.flatMap((i) => i.options); evt1.options = question.list.flatMap((i) => i.options);

View File

@@ -196,7 +196,7 @@ watch(status, (val) => {
getCode(); getCode();
} }
}); });
onMounted(async () => { onMounted(async() => {
fetchInfo(); fetchInfo();
}); });
</script> </script>
@@ -211,10 +211,10 @@ onMounted(async () => {
.content { .content {
margin: 10px; margin: 10px;
padding-bottom: 25px;
border-radius: 8px; border-radius: 8px;
background: #fff; background: #fff;
box-shadow: 0 0 2px rgba(0, 0, 0, 0.1); box-shadow: 0 0 2px rgba(0, 0, 0, 0.1);
padding-bottom: 25px;
.qrcode { .qrcode {
display: flex; display: flex;
@@ -234,8 +234,8 @@ onMounted(async () => {
} }
.desc { .desc {
font-size: 13px;
margin-top: 8px; margin-top: 8px;
font-size: 13px;
line-height: 16px; line-height: 16px;
} }
} }