diff --git a/components.d.ts b/components.d.ts index fd0daa6..4dccc9c 100644 --- a/components.d.ts +++ b/components.d.ts @@ -11,6 +11,7 @@ declare module 'vue' { Contenteditable: typeof import('./src/components/contenteditable.vue')['default'] ElButton: typeof import('element-plus/es')['ElButton'] ElCard: typeof import('element-plus/es')['ElCard'] + ElDialog: typeof import('element-plus/es')['ElDialog'] ElDropdown: typeof import('element-plus/es')['ElDropdown'] ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem'] ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu'] @@ -22,6 +23,7 @@ declare module 'vue' { ElSpace: typeof import('element-plus/es')['ElSpace'] ElTable: typeof import('element-plus/es')['ElTable'] ElTableColumn: typeof import('element-plus/es')['ElTableColumn'] + ElTag: typeof import('element-plus/es')['ElTag'] ElText: typeof import('element-plus/es')['ElText'] Index: typeof import('./src/components/Analysis/Index.vue')['default'] MarketItem: typeof import('./src/components/MarketItem/MarketItem.vue')['default'] @@ -34,6 +36,7 @@ declare module 'vue' { VanCellGroup: typeof import('vant/es')['CellGroup'] VanCheckbox: typeof import('vant/es')['Checkbox'] VanCheckboxGroup: typeof import('vant/es')['CheckboxGroup'] + VanCol: typeof import('vant/es')['Col'] VanDivider: typeof import('vant/es')['Divider'] VanField: typeof import('vant/es')['Field'] VanIcon: typeof import('vant/es')['Icon'] @@ -44,6 +47,7 @@ declare module 'vue' { VanPopup: typeof import('vant/es')['Popup'] VanRadio: typeof import('vant/es')['Radio'] VanRadioGroup: typeof import('vant/es')['RadioGroup'] + VanRow: typeof import('vant/es')['Row'] VanSearch: typeof import('vant/es')['Search'] VanSpace: typeof import('vant/es')['Space'] VanStepper: typeof import('vant/es')['Stepper'] @@ -60,4 +64,7 @@ declare module 'vue' { YLPicker: typeof import('./src/components/YLPicker.vue')['default'] YLSelect: typeof import('./src/components/YLSelect.vue')['default'] } + export interface ComponentCustomProperties { + vLoading: typeof import('element-plus/es')['ElLoadingDirective'] + } } diff --git a/src/api/anslysis/aiInsight.ts b/src/api/anslysis/aiInsight.ts index 62b344f..1534fb9 100644 --- a/src/api/anslysis/aiInsight.ts +++ b/src/api/anslysis/aiInsight.ts @@ -5,9 +5,21 @@ import request from '@/utils/request'; * @param sn 循环题组sn * @param params 可选的页数信息 */ -export function analysisInsights (sn: string, params?: ParticalParams) { +export function analysisInsights(sn: string, params?: ParticalParams) { return request({ url: `/console/surveys/${sn}/analysis_insights_h5`, params }); -} \ No newline at end of file +} +/** + * ai 洞察检查分析是否完成 + * @param sn 循环题组sn + * @param data {1|2} 1=AI样本标记;2=AI洞察 + */ +export function checkAnalysisSatus(sn: string, data?: 1 | 2) { + return request({ + url: `/console/surveys/${sn}/status`, + method: 'post', + data + }); +} diff --git a/src/api/survey/index.js b/src/api/survey/index.js index 40c983b..881ebd7 100644 --- a/src/api/survey/index.js +++ b/src/api/survey/index.js @@ -19,11 +19,11 @@ export function getSurveyInfo(sn) { /** * 问题分析接口 - * @param sn + * @param sn * @param data {import('@/api/types/analysis.js').AnalysisParam} * @returns {Promise> | *} */ -export function surveyAnalysis(sn, data) { +export function surveyAnalysis(sn, data = {}) { return request({ url: `/console/surveys/${sn}/chart_analysis`, method: 'post', diff --git a/src/components/Analysis/Index.vue b/src/components/Analysis/Index.vue index 70fade4..e24e46f 100644 --- a/src/components/Analysis/Index.vue +++ b/src/components/Analysis/Index.vue @@ -3,94 +3,23 @@ import { ref, useTemplateRef } from 'vue'; import { showToast } from 'vant'; import { useSetPieChart } from '@/hooks/chart/usePieChart'; import { surveys } from '@/components/Analysis/hooks/useSurvey'; +import { questionTypeMap } from '@/utils/question/typeMapping'; +// const info = defineModel('info', { required: true }); +// series 信息 +const series = defineModel('series', { required: true }); // 饼图 dom 结构 const pieChart = useTemplateRef('pieChart'); -useSetPieChart(pieChart, [1], { title: false, ledge: false }); - -// 任务数据 -const taskData = ref({ - title: '问卷A', - progress: 100, - deadline: '2025-03-31至04-01', - creator: '张三', - creationMethod: '移动端', - creationTime: '2025-03-04', - responseCount: 10, - responseRate: '10%', - submissionRate: '10%', - status: '草稿中' -}); - -// 图表数据 -const chartData = ref([ - { - name: '选项1', - value: 66.77, - color: '#F56C6C' - }, - { - name: '选项2', - value: 33.33, - color: '#F7BA2A' - }, - { - name: '选项3', - value: 0, - color: '#67C23A' - }, - { - name: '选项4', - value: 0, - color: '#409EFF' - } -]); - -// 导航按钮点击事件 -const handlePrev = () => { - showToast('点击了上一个问题'); -}; - -const handleNext = () => { - showToast('点击了下一个问题'); -}; - +useSetPieChart(pieChart, series.value, { title: false, ledge: false }); diff --git a/src/hooks/chart/usePieChart.ts b/src/hooks/chart/usePieChart.ts index a2f91db..44c7d6c 100644 --- a/src/hooks/chart/usePieChart.ts +++ b/src/hooks/chart/usePieChart.ts @@ -9,27 +9,27 @@ const pieChart = ref(); /** * 定义数据集 */ -const series = ref([ - { - name: 'Access From', - type: 'pie', - radius: '50%', - data: [ - { value: 1048, name: 'Search Engine' }, - { value: 735, name: 'Direct' }, - { value: 580, name: 'Email' }, - { value: 484, name: 'Union Ads' }, - { value: 300, name: 'Video Ads' } - ], - emphasis: { - itemStyle: { - shadowBlur: 10, - shadowOffsetX: 0, - shadowColor: 'rgba(0, 0, 0, 0.5)' - } - } - } -]); +// const series = ref([ +// { +// name: 'Access From', +// type: 'pie', +// radius: '50%', +// data: [ +// { value: 1048, name: 'Search Engine' }, +// { value: 735, name: 'Direct' }, +// { value: 580, name: 'Email' }, +// { value: 484, name: 'Union Ads' }, +// { value: 300, name: 'Video Ads' } +// ], +// emphasis: { +// itemStyle: { +// shadowBlur: 10, +// shadowOffsetX: 0, +// shadowColor: 'rgba(0, 0, 0, 0.5)' +// } +// } +// } +// ]); /** * 饼图的 option @@ -38,18 +38,18 @@ const option = ref(pieOption); function useSetPieChart( dom: Readonly>, - data: any[], + series: any, opts: optsType = {} ): void { - for (let item in opts) { + if (!series) return; + for (const item in opts) { if (item === 'legend') !opts[item] && deleteLegend(); else if (item === 'title') !opts[item] && deleteTitle(); } // 检测边界范围 dom 和 data 是否存在 onMounted(() => { - // console.log(dom); - if (!dom || data.length === 0) return; + if (!dom || series.data.length === 0) return; // 在 dom 挂载之后,显示饼图 pieChart.value = chart.init(dom.value); pieChart.value.setOption(option.value, opts); diff --git a/src/utils/question/typeMapping.ts b/src/utils/question/typeMapping.ts new file mode 100644 index 0000000..450d931 --- /dev/null +++ b/src/utils/question/typeMapping.ts @@ -0,0 +1,7 @@ +const map = new Map(); + +map.set(1, '单选题'); +map.set(5, '数值打分题'); +map.set(9, '矩阵单选'); + +export { map as questionTypeMap }; diff --git a/src/views/Survey/components/SurveyItem.vue b/src/views/Survey/components/SurveyItem.vue index 0a2db2b..7352ea4 100644 --- a/src/views/Survey/components/SurveyItem.vue +++ b/src/views/Survey/components/SurveyItem.vue @@ -11,7 +11,13 @@ import { showDialog, showFailToast, showSuccessToast } from 'vant'; import { finish } from '@/api/survey'; import { copySurveys } from '@/api/home'; import { useRouter } from 'vue-router'; -import { form, fetchSurveys, deleteItem, saveTemplate, currentSurvey } from '@/views/Survey/hooks/useSurveyData'; +import { + form, + fetchSurveys, + deleteItem, + saveTemplate, + currentSurvey +} from '@/views/Survey/hooks/useSurveyData'; // router const router = useRouter(); @@ -20,7 +26,7 @@ const emit = defineEmits(['post-analysis', 'post-surveys']); const survey = defineModel('survey', { required: true }); const isAnalysis = defineModel('isAnalysis', { default: false, type: Boolean }); const postAnalysis = defineModel('post-analysis'); -function setImg (code: number) { +function setImg(code: number) { const imageMap: { [key: number]: string } = { 11: png11, 13: png13, @@ -35,7 +41,7 @@ function setImg (code: number) { return imageMap[code] || png11; } -function editItem (item: SurveyItem) { +function editItem(item: SurveyItem) { router.push({ path: '/create', query: { @@ -44,7 +50,7 @@ function editItem (item: SurveyItem) { }); } -function toPreview (item: SurveyItem) { +function toPreview(item: SurveyItem) { router.push({ path: '/preview', query: { @@ -59,7 +65,7 @@ function toPreview (item: SurveyItem) { * 跳转 统计分析 页面 * @param item */ -function toAnalysis (item: SurveyItem) { +function toAnalysis(item: SurveyItem) { // 设置当前的节点信息 currentSurvey.value = item; // 跳转 @@ -71,7 +77,7 @@ function toAnalysis (item: SurveyItem) { }); } -function toPublish (item: SurveyItem) { +function toPublish(item: SurveyItem) { if (item.status === 1) { showDialog({ title: `确定要取消投放${item.project_name}?`, @@ -98,7 +104,7 @@ function toPublish (item: SurveyItem) { } } -function copyItem (item: SurveyItem) { +function copyItem(item: SurveyItem) { showDialog({ title: `确认复制问卷${item.project_name} ?`, showCancelButton: true, @@ -119,7 +125,6 @@ function copyItem (item: SurveyItem) { // on cancel }); } - \ No newline at end of file + diff --git a/src/views/Survey/views/Analysis/Index.vue b/src/views/Survey/views/Analysis/Index.vue index e8125a6..f50409c 100644 --- a/src/views/Survey/views/Analysis/Index.vue +++ b/src/views/Survey/views/Analysis/Index.vue @@ -4,16 +4,21 @@ import SurveyItem from '@/views/Survey/components/SurveyItem.vue'; import LogicInfo from '@/views/Survey/views/Analysis/components/LogicInfo/Index.vue'; import AiInsightResults from '@/views/Survey/views/Analysis/components/AiInsightResults/Index.vue'; import { useRoute } from 'vue-router'; -import { useFetchAnalysis, postAnalysis, aiInsightsConfig } from '@/views/Survey/views/Analysis/hooks/useAnalysis'; +import { + useFetchAnalysis, + postAnalysis, + aiInsightsConfig +} from '@/views/Survey/views/Analysis/hooks/useAnalysis'; import Wait from '@/views/Survey/views/Analysis/components/Wait/Index.vue'; +import AnalysisInfo from '@/views/Survey/views/Analysis/components/AnalysisInfo/Index.vue'; const route = useRoute(); /** * 如果当前问卷的数据不存在,重新获取数据 */ -if (!currentSurvey.value) fetchSingleSurvey(route.query.sn); +if (!currentSurvey.value) fetchSingleSurvey(route.query.sn as string); -useFetchAnalysis(route.query.sn); +useFetchAnalysis(route.query.sn as string); - - - + + - + \ No newline at end of file + diff --git a/src/views/Survey/views/Analysis/components/AnalysisInfo/Index.vue b/src/views/Survey/views/Analysis/components/AnalysisInfo/Index.vue new file mode 100644 index 0000000..64041d8 --- /dev/null +++ b/src/views/Survey/views/Analysis/components/AnalysisInfo/Index.vue @@ -0,0 +1,19 @@ + + + diff --git a/src/views/Survey/views/Analysis/components/AnalysisInfo/hooks/pieSeries.ts b/src/views/Survey/views/Analysis/components/AnalysisInfo/hooks/pieSeries.ts new file mode 100644 index 0000000..2d332ce --- /dev/null +++ b/src/views/Survey/views/Analysis/components/AnalysisInfo/hooks/pieSeries.ts @@ -0,0 +1,39 @@ +import { ref } from 'vue'; + +export const series = ref({ + name: 'Access From', + type: 'pie', + radius: ['40%', '70%'], + avoidLabelOverlap: false, + label: { + show: false, + position: 'center' + }, + emphasis: { + label: { + show: true, + fontSize: 40, + fontWeight: 'bold' + } + }, + labelLine: { + show: false + }, + data: [] +}); + +export function formatData(data: any) { + console.log(data); + const { option } = data; + + series.value.data = option.map((item) => { + return { + value: item.number, + name: item.title + }; + }); + + console.log(`series data`, series.value); + + return series.value; +} diff --git a/src/views/Survey/views/Analysis/hooks/useAnalysis.ts b/src/views/Survey/views/Analysis/hooks/useAnalysis.ts index e0e7722..8137d38 100644 --- a/src/views/Survey/views/Analysis/hooks/useAnalysis.ts +++ b/src/views/Survey/views/Analysis/hooks/useAnalysis.ts @@ -1,15 +1,15 @@ import { surveyAnalysis } from '@/api/survey'; -import { ref } from 'vue'; -import { analysisInsights } from '@/api/anslysis/aiInsight'; +import { onMounted, ref } from 'vue'; +import { analysisInsights, checkAnalysisSatus } from '@/api/anslysis/aiInsight'; type AiInsightType = { - visible: boolean, - timer: NodeJS.Timeout | undefined -} + visible: boolean; + timer: NodeJS.Timeout | undefined; +}; // ai 智能洞察 export const aiInsightsConfig = ref({ visible: false, - timer: void 0 + timer: undefined }); const questionAnalysis = ref(); @@ -19,26 +19,31 @@ const params: AnalysisParam = { source: 1 }; -export function postAnalysis (sn: string) { - console.log(sn); +export function postAnalysis(sn: string) { aiInsightsConfig.value.visible = true; - // analysisInsights(sn); + analysisInsights(sn); if (!aiInsightsConfig.value.timer) { // 每 1 s 检查一次是否分析完成 aiInsightsConfig.value.timer = setInterval(() => { checkAnalysis(sn); }, 1000); } + + onMounted(() => { + // 当组件取消挂载时, 取消 interval 定时 + clearInterval(aiInsightsConfig.value.timer); + }); } -export function checkAnalysis (sn: string) { - console.log(sn); +export async function checkAnalysis(sn: string) { + const res = checkAnalysisSatus(sn, 2); + console.log(res); } -async function useFetchAnalysis (sn: string) { - const res = await surveyAnalysis(sn, params); +async function useFetchAnalysis(sn: string) { + const res = await surveyAnalysis(sn); questionAnalysis.value = res.data.data; console.log(`question analysis`, questionAnalysis.value); } -export { useFetchAnalysis, questionAnalysis }; \ No newline at end of file +export { useFetchAnalysis, questionAnalysis };