@qxs-bns/components 0.0.32 → 0.0.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/es/package.json.mjs +1 -1
- package/es/src/data-chart/src/components/bar.vue.mjs +1 -1
- package/es/src/data-chart/src/components/bar.vue.mjs.map +1 -1
- package/es/src/data-chart/src/components/line.vue2.mjs +1 -1
- package/es/src/data-chart/src/components/line.vue2.mjs.map +1 -1
- package/es/src/data-chart/src/components/pie.vue.mjs +1 -1
- package/es/src/data-chart/src/components/pie.vue.mjs.map +1 -1
- package/es/src/file-upload/src/file-upload.vue.mjs.map +1 -1
- package/es/src/photo-crop-tool/src/photo-crop-tool.vue.mjs +1 -1
- package/es/src/photo-crop-tool/src/photo-crop-tool.vue.mjs.map +1 -1
- package/es/src/subject-action/src/subject-action.vue.mjs +1 -1
- package/es/src/subject-action/src/subject-action.vue.mjs.map +1 -1
- package/es/src/subject-list/index.mjs.map +1 -1
- package/es/src/subject-list/src/components/subject-single.vue.mjs +1 -1
- package/es/src/subject-list/src/components/subject-single.vue.mjs.map +1 -1
- package/lib/package.json.cjs +1 -1
- package/lib/src/data-chart/src/components/bar.vue.cjs +1 -1
- package/lib/src/data-chart/src/components/bar.vue.cjs.map +1 -1
- package/lib/src/data-chart/src/components/line.vue2.cjs +1 -1
- package/lib/src/data-chart/src/components/line.vue2.cjs.map +1 -1
- package/lib/src/data-chart/src/components/pie.vue.cjs +1 -1
- package/lib/src/data-chart/src/components/pie.vue.cjs.map +1 -1
- package/lib/src/file-upload/src/file-upload.vue.cjs.map +1 -1
- package/lib/src/photo-crop-tool/src/photo-crop-tool.vue.cjs +1 -1
- package/lib/src/photo-crop-tool/src/photo-crop-tool.vue.cjs.map +1 -1
- package/lib/src/subject-action/src/subject-action.vue.cjs +1 -1
- package/lib/src/subject-action/src/subject-action.vue.cjs.map +1 -1
- package/lib/src/subject-list/index.cjs.map +1 -1
- package/lib/src/subject-list/src/components/subject-single.vue.cjs +1 -1
- package/lib/src/subject-list/src/components/subject-single.vue.cjs.map +1 -1
- package/package.json +2 -2
- package/theme-chalk/base.css +1 -1
- package/theme-chalk/image-upload.css +1 -1
- package/theme-chalk/index.css +1 -1
- package/theme-chalk/subject-list.css +1 -1
- package/types/src/data-chart/index.d.ts +17 -1
- package/types/src/data-chart/index.d.ts.map +1 -1
- package/types/src/data-chart/src/components/area.vue.d.ts +8 -0
- package/types/src/data-chart/src/components/area.vue.d.ts.map +1 -0
- package/types/src/data-chart/src/components/bar.vue.d.ts +9 -0
- package/types/src/data-chart/src/components/bar.vue.d.ts.map +1 -0
- package/types/src/data-chart/src/components/card.vue.d.ts +27 -0
- package/types/src/data-chart/src/components/card.vue.d.ts.map +1 -0
- package/types/src/data-chart/src/components/empty.vue.d.ts +11 -0
- package/types/src/data-chart/src/components/empty.vue.d.ts.map +1 -0
- package/types/src/data-chart/src/components/funnel.vue.d.ts +8 -0
- package/types/src/data-chart/src/components/funnel.vue.d.ts.map +1 -0
- package/types/src/data-chart/src/components/line.vue.d.ts +9 -0
- package/types/src/data-chart/src/components/line.vue.d.ts.map +1 -0
- package/types/src/data-chart/src/components/pie.vue.d.ts +9 -0
- package/types/src/data-chart/src/components/pie.vue.d.ts.map +1 -0
- package/types/src/data-chart/src/components/radar.vue.d.ts +8 -0
- package/types/src/data-chart/src/components/radar.vue.d.ts.map +1 -0
- package/types/src/data-chart/src/components/scatter-simple.vue.d.ts +8 -0
- package/types/src/data-chart/src/components/scatter-simple.vue.d.ts.map +1 -0
- package/types/src/data-chart/src/components/scatter.vue.d.ts +8 -0
- package/types/src/data-chart/src/components/scatter.vue.d.ts.map +1 -0
- package/types/src/data-chart/src/components/table.vue.d.ts +27 -0
- package/types/src/data-chart/src/components/table.vue.d.ts.map +1 -0
- package/types/src/data-chart/src/data-chart.vue.d.ts +16 -0
- package/types/src/data-chart/src/data-chart.vue.d.ts.map +1 -0
- package/types/src/file-upload/index.d.ts +27 -1
- package/types/src/file-upload/index.d.ts.map +1 -1
- package/types/src/file-upload/src/file-upload.vue.d.ts +20 -0
- package/types/src/file-upload/src/file-upload.vue.d.ts.map +1 -0
- package/types/src/fixed-action-bar/index.d.ts +53 -1
- package/types/src/fixed-action-bar/index.d.ts.map +1 -1
- package/types/src/fixed-action-bar/src/fixed-action-bar.vue.d.ts +31 -0
- package/types/src/fixed-action-bar/src/fixed-action-bar.vue.d.ts.map +1 -0
- package/types/src/image-upload/index.d.ts +44 -1
- package/types/src/image-upload/index.d.ts.map +1 -1
- package/types/src/image-upload/src/image-upload.vue.d.ts +34 -0
- package/types/src/image-upload/src/image-upload.vue.d.ts.map +1 -0
- package/types/src/photo-crop-tool/index.d.ts +52 -1
- package/types/src/photo-crop-tool/index.d.ts.map +1 -1
- package/types/src/photo-crop-tool/src/photo-crop-tool.vue.d.ts +65 -0
- package/types/src/photo-crop-tool/src/photo-crop-tool.vue.d.ts.map +1 -0
- package/types/src/subject-action/index.d.ts +85 -1
- package/types/src/subject-action/index.d.ts.map +1 -1
- package/types/src/subject-action/src/subject-action.vue.d.ts +87 -0
- package/types/src/subject-action/src/subject-action.vue.d.ts.map +1 -0
- package/types/src/subject-layout/index.d.ts +25 -1
- package/types/src/subject-layout/index.d.ts.map +1 -1
- package/types/src/subject-layout/src/subject-layout.vue.d.ts +42 -0
- package/types/src/subject-layout/src/subject-layout.vue.d.ts.map +1 -0
- package/types/src/subject-list/index.d.ts +18 -2
- package/types/src/subject-list/index.d.ts.map +1 -1
- package/types/src/subject-list/src/components/SubjectPageEnd.vue.d.ts +24 -0
- package/types/src/subject-list/src/components/SubjectPageEnd.vue.d.ts.map +1 -0
- package/types/src/subject-list/src/components/SubjectRichText.vue.d.ts +25 -0
- package/types/src/subject-list/src/components/SubjectRichText.vue.d.ts.map +1 -0
- package/types/src/subject-list/src/components/subject-blank-fill.vue.d.ts +32 -0
- package/types/src/subject-list/src/components/subject-blank-fill.vue.d.ts.map +1 -0
- package/types/src/subject-list/src/components/subject-scale.vue.d.ts +29 -0
- package/types/src/subject-list/src/components/subject-scale.vue.d.ts.map +1 -0
- package/types/src/subject-list/src/components/subject-single.vue.d.ts +37 -0
- package/types/src/subject-list/src/components/subject-single.vue.d.ts.map +1 -0
- package/types/src/subject-list/src/components/subject-text-fill.vue.d.ts +34 -0
- package/types/src/subject-list/src/components/subject-text-fill.vue.d.ts.map +1 -0
- package/types/src/subject-list/src/subject-list.vue.d.ts +21 -0
- package/types/src/subject-list/src/subject-list.vue.d.ts.map +1 -0
- package/types/src/subject-type/index.d.ts +5 -1
- package/types/src/subject-type/index.d.ts.map +1 -1
- package/types/src/subject-type/src/subject-type.vue.d.ts +7 -0
- package/types/src/subject-type/src/subject-type.vue.d.ts.map +1 -0
- package/types/src/tiny-mce-editor/index.d.ts +17 -1
- package/types/src/tiny-mce-editor/index.d.ts.map +1 -1
- package/types/src/tiny-mce-editor/src/tiny-mce-editor.vue.d.ts +32 -0
- package/types/src/tiny-mce-editor/src/tiny-mce-editor.vue.d.ts.map +1 -0
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"subject-single.vue.mjs","sources":["../../../../../../../packages/components/src/subject-list/src/components/subject-single.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { CirclePlus, Remove } from '@element-plus/icons-vue'\nimport { useNamespace } from '@qxs-bns/hooks'\nimport SubjectAction from '../../../subject-action/src/subject-action.vue'\nimport SubjectLayout from '../../../subject-layout/src/subject-layout.vue'\nimport TinyMceEditor from '../../../tiny-mce-editor/src/tiny-mce-editor.vue'\nimport { setGuid } from '@qxs-bns/utils'\nimport { ElMessage } from 'element-plus'\n\ndefineOptions({\n name: 'QxsSubjectSingle',\n})\nconst props = defineProps<{\n orderIndex: number\n title?: string\n isSave: boolean\n showAction?: boolean\n type: 'single' | 'multiple' | 'sort'\n isEdit: boolean\n isSet: boolean\n answerList?: any\n leastAnswerCount?: number\n analysis?: string\n examExpand?: string\n examRichTextContent?: string\n showAnalysis?: boolean\n examAnswerRelationType?: number\n customId?: number\n examId?: number\n isKey: boolean\n answerCheckType: number\n}>()\nconst emits = defineEmits(['move', 'save', 'delete', 'edit', 'add', 'setRelation'])\n\nconst attrs = useAttrs()\n\nconst answersIndex = ref(0)\nconst isKey = ref(false)\nconst answerCheckType = ref(1)\nconst examAnswerRelationType = ref(1)\nconst answers = ref<{\n title: string\n isCorrect: boolean\n orderIndex?: number\n resultItem?: string\n customAnswerId?: string\n answerRelations?: {\n relationExamId: number\n relationAnswers: {\n relationAnswerId: number\n relationAnswerIndex: number\n }[]\n }[]\n}[]>([{\n title: '',\n isCorrect: false,\n}, {\n title: '',\n isCorrect: false,\n}, {\n title: '',\n isCorrect: false,\n}, {\n title: '',\n isCorrect: false,\n}])\n\nconst leastAnswerCount = ref()\nconst title = ref('')\nconst analysis = ref('')\nconst showRichText = ref(false)\nconst richText = ref('')\nconst startTime = ref(0)\nconst showRichContent = ref(false)\nconst resultItem = ref<string>('')\nconst titlePlaceholder = computed(() => {\n if (props.type === 'single') {\n return '单选题'\n }\n else if (props.type === 'multiple') {\n return '多选题'\n }\n else {\n return '排序题'\n }\n})\n\nconst orderList = ref<string[]>([])\n\nconst leastAnswerOptions = computed(() => {\n const items = []\n const length = answers.value.length\n for (let count = length; count > 1; count--) {\n items.push({\n label: `至少选择${count}项`,\n value: count,\n })\n }\n return items.reverse()\n})\nfunction addAnswer() {\n if (props.isSave) {\n return\n }\n answers.value.push({\n title: '',\n isCorrect: false,\n customAnswerId: setGuid()\n })\n}\n\nfunction deleteAnswer(index: number) {\n if (answers.value.length < 3 || props.isSave) {\n return\n }\n answers.value.splice(index, 1)\n}\n\nfunction setCorrect(it: any, event: any) {\n if (props.type === 'single') {\n // 单选题:确保只有一个支持选项\n if (event) {\n answers.value.forEach((answer: any) => {\n if (answer !== it) {\n answer.isCorrect = false\n }\n })\n }\n it.isCorrect = event\n } else if (props.type === 'multiple') {\n // 多选题:可以有多个支持选项\n it.isCorrect = event\n }\n}\nfunction setRelation(item: any) {\n item.customAnswerId = item.examAnswerId || setGuid()\n emits('setRelation', props.customId, item)\n}\n\nfunction deleteRichText() {\n showRichText.value = false\n richText.value = ''\n}\n\nfunction save() {\n if (!title.value) {\n ElMessage.error('题目标题不能为空!')\n return\n }\n let msg = ''\n let isSetCorrectAnswer = false\n // let examAnswerRelationType = null\n let correctAnswerCount = 0\n if (props.type === 'multiple' || props.type === 'single') {\n answers.value.forEach((v: any, i: number) => {\n if (!v.title) {\n msg += `选项${String.fromCharCode(65 + i)}未填写。`\n }\n if (v.isCorrect) {\n isSetCorrectAnswer = true\n correctAnswerCount++\n }\n // if (v.resultItem) {\n // examAnswerRelationType = 1\n // }\n // if (v.answerRelations?.length) {\n // examAnswerRelationType = 2\n // }\n })\n }\n else if (props.type === 'sort') {\n // 如果设置了支持选项\n if (orderList.value.length) {\n isSetCorrectAnswer = true\n }\n }\n if (msg) {\n ElMessage.error(msg)\n return\n }\n\n const uniqueAnswer = new Set(answers.value.map((item: any) => item.title))\n\n if (uniqueAnswer.size !== answers.value.length) {\n ElMessage.error('选项不能重复')\n return\n }\n\n if (props.type === 'multiple') {\n if (correctAnswerCount === 1) {\n ElMessage.error('请至少设置两个支持选项')\n return\n }\n\n if (isSetCorrectAnswer && correctAnswerCount < leastAnswerCount.value) {\n ElMessage.error('至少选几项与支持选项数不符')\n return\n }\n }\n console.log(answerCheckType.value, 111)\n \n\n if(answerCheckType.value === 2 || answerCheckType.value === 3) {\n // 必须有设置支持选项\n if (!isSetCorrectAnswer) {\n ElMessage.error('请设置支持选项')\n return\n }\n }\n\n emits('save', {\n title: title.value,\n answers: answers.value.map((item: any, index: number) => {\n return { ...item, orderIndex: index + 1 }\n }),\n examExpand: orderList.value.map((i: string) => i.charCodeAt(0) - 65 + 1).join(','),\n analysis: analysis.value,\n isSetCorrectAnswer,\n leastAnswerCount: leastAnswerCount.value,\n examRichTextContent: showRichText.value ? richText.value : '',\n examAnswerRelationType: examAnswerRelationType.value,\n isKey: isKey.value,\n answerCheckType: answerCheckType.value\n })\n}\n\nfunction init() {\n if (props.title) {\n title.value = props.title\n }\n // const customId = props.id || setGuid()\n\n if (props.answerCheckType) {\n answerCheckType.value = props.answerCheckType\n }\n if (props.isKey) {\n isKey.value = props.isKey\n }\n\n if (props.examAnswerRelationType) {\n examAnswerRelationType.value = props.examAnswerRelationType\n }\n\n if (props.answerList && props.answerList.length) {\n answers.value = props.answerList\n }\n\n if (props.leastAnswerCount) {\n leastAnswerCount.value = props.leastAnswerCount\n }\n\n if (props.examExpand) {\n // 设置支持选项 props.examExpand里是答案id\n if (props.examExpand) {\n const correctAnswerIdList = props.examExpand.split(',')\n\n // 遍历 correctAnswerIdList,直接在 props.answerList 中查找对应的 orderIndex 并转换成字母\n orderList.value = correctAnswerIdList.map((id: string) => {\n const answer = props.answerList.find((item: any) => item.answerId?.toString() === id)\n return answer ? String.fromCharCode(65 + answer.orderIndex - 1) : id\n }).filter(Boolean) // 过滤掉任何可能的空字符串\n }\n }\n\n if (props.analysis) {\n analysis.value = props.analysis\n }\n\n if (props.examRichTextContent) {\n richText.value = props.examRichTextContent\n showRichText.value = true\n }\n}\nfunction onOpenResult(i: number) {\n answersIndex.value = i\n resultItem.value = answers.value[i].resultItem || ''\n showRichContent.value = true\n}\n\nfunction onSaveResult() {\n answers.value[answersIndex.value].resultItem = resultItem.value || ''\n showRichContent.value = false\n}\nfunction onCloseResult() {\n showRichContent.value = false\n resultItem.value = ''\n}\nfunction setKey(key: boolean) {\n isKey.value = key\n}\nfunction setAnswerSetting(type: number) {\n answerCheckType.value = type\n}\n\nfunction add(type: string, canSet: boolean) {\n emits('add', type, canSet? props.examAnswerRelationType: null)\n}\n// 监听isEdit\nwatch(() => props.isEdit, () => {\n if (props.isEdit) {\n startTime.value = new Date().getTime()\n }\n})\n\nconst relationLength = computed(() => {\n return (v: any) => {\n let count = 0\n v.forEach((item: any) => {\n if (item.relationAnswers) {\n count += item.relationAnswers.length\n }\n })\n return count\n }\n})\n\nconst ns = useNamespace('subject-single')\n\nonMounted(init)\n</script>\n\n<template>\n <div :class=\"ns.e('single-exam')\">\n <SubjectLayout\n :show-edit=\"isEdit\"\n >\n <template #preview>\n <div class=\"preview\">\n <div>\n <span class=\"title\">\n {{ orderIndex + 1 }}.{{ title }}\n <span v-if=\"type === 'single'\">(单选题)</span>\n <span v-else-if=\"['multiple', 'sort'].includes(type)\">\n ({{ titlePlaceholder }}{{ leastAnswerCount ? `至少选${leastAnswerCount}项${type === 'sort' ? '并排序' : ''}` : '' }})\n </span>\n </span>\n </div>\n <div v-if=\"showRichText\">\n <div v-html=\"richText\" />\n </div>\n <div class=\"preview-answer\">\n <template v-if=\"type === 'sort'\">\n <el-checkbox\n v-for=\"(item, index) in answers\"\n :key=\"index\"\n class=\"radio\"\n :disabled=\"true\"\n >\n <span class=\"order\">\n {{ String.fromCharCode(65 + index) }}.\n </span>\n {{ item.title }}\n </el-checkbox>\n </template>\n <template v-else>\n <el-radio\n v-for=\"(item, index) in answers\"\n :key=\"index\"\n class=\"radio\"\n value=\"disabled\"\n disabled\n >\n <span class=\"order\">\n {{ String.fromCharCode(65 + index) }}.\n </span>\n {{ item.title }} \n {{ item.isCorrect ? '(支持选项)' : '' }} \n {{ examAnswerRelationType === 1 ? (item.resultItem? '(已设置结果项)' : '(未设置结果项)' ) : ''}} \n {{ examAnswerRelationType === 2 ? (item.answerRelations?.length? '(已设置关联)' : '(未设置关联)') : '' }}\n </el-radio>\n </template>\n </div>\n </div>\n </template>\n <template v-if=\"isEdit\" #edit>\n <div class=\"flex\" :class=\"[{ 'margin-bottom': showRichText }]\">\n <div class=\"label flex flex-justify-center\">\n <span>题目:</span>\n </div>\n <div style=\"flex: 1;\">\n <el-input\n v-model=\"title\"\n type=\"textarea\"\n :rows=\"2\"\n :placeholder=\"`【${titlePlaceholder}】请输入问题`\"\n :disabled=\"isSave\"\n show-word-limit\n maxlength=\"200\"\n class=\"margin-bottom\"\n />\n </div>\n </div>\n <div class=\"margin-bottom flex flex-items-center\">\n <div class=\"label flex flex-justify-center\">\n <span>设置:</span>\n </div>\n <el-select\n v-if=\"['multiple', 'sort'].includes(type)\"\n v-model=\"leastAnswerCount\"\n style=\"width: 150px;\"\n placeholder=\"至少选择几项\"\n :disabled=\"isSave\"\n >\n <el-option\n v-for=\"item in leastAnswerOptions\"\n :key=\"item.value\"\n :value=\"item.value\"\n :label=\"item.label\"\n >\n </el-option>\n </el-select>\n </div>\n <div class=\"margin-bottom answer-list\">\n <div\n v-for=\"(item, index) in answers\"\n :key=\"index\"\n class=\"answer-item flex flex-items-center\"\n >\n <span class=\"order\">{{ String.fromCharCode(65 + index) }}.</span>\n <el-input\n v-model=\"item.title\"\n class=\"input\"\n show-word-limit\n maxlength=\"100\"\n :placeholder=\"`选项${String.fromCharCode(65 + index)}`\"\n :disabled=\"isSave\"\n />\n <el-checkbox\n v-if=\"['single', 'multiple'].includes(type)\"\n v-model=\"item.isCorrect\"\n :class=\"[{ 'is-correct': item.isCorrect }]\"\n :disabled=\"isSave\"\n style=\"margin-left: 10px;\"\n @change=\"(event: any) => setCorrect(item, event)\"\n >\n 支持选项 \n </el-checkbox>\n <el-icon class=\"icon\">\n <CirclePlus\n :class=\"[{ disabled: isSave }]\"\n @click=\"addAnswer\"\n />\n </el-icon>\n <el-icon class=\"icon\">\n <Remove\n :class=\"[{ disabled: answers.length < 3 || isSave }]\"\n @click=\"deleteAnswer(index)\"\n />\n </el-icon>\n <el-link\n v-if=\"examAnswerRelationType === 1\"\n type=\"primary\"\n class=\"margin-left-10\"\n @click=\"onOpenResult(index)\"\n >\n <span>{{ item.resultItem ? '编辑结果' : '添加结果' }}</span>\n </el-link>\n <el-link\n v-if=\"examAnswerRelationType === 2\"\n type=\"primary\"\n class=\"margin-left-10\"\n @click=\"setRelation(item)\"\n >\n <span>{{ item.answerRelations?.length ? `关联了${relationLength(item.answerRelations)}项` : '关联检查' }}</span>\n </el-link>\n </div>\n </div>\n <div v-if=\"type === 'sort'\" class=\"margin-bottom flex flex-items-center\">\n <div class=\"label flex flex-justify-end\">\n <span>排序答案:</span>\n </div>\n <div style=\"flex: 1;\">\n <el-select\n v-model=\"orderList\"\n mode=\"multiple\"\n style=\"width: 360px;\"\n placeholder=\"请按顺序选择排序答案\"\n :show-arrow=\"true\"\n >\n <!-- :options=\"[...Array(answers.length)].map((_, i) => ({ value: String.fromCharCode(65 + i) }))\" -->\n <el-option\n v-for=\"(item, index) in answers\"\n :key=\"index\"\n :label=\"item.title\"\n :value=\"String.fromCharCode(65 + index)\"\n />\n </el-select>\n </div>\n </div>\n <div\n v-if=\"showAnalysis\"\n class=\"flex\"\n >\n <div class=\"label flex flex-justify-center\">\n <span>解析:</span>\n </div>\n <div style=\"flex: 1;\">\n <el-input\n v-model=\"analysis\"\n type=\"textarea\"\n :rows=\"2\"\n placeholder=\"请输入题目解析\"\n />\n </div>\n </div>\n <div v-if=\"showRichText\" class=\"margin-bottom flex\">\n <div class=\"label flex flex-justify-center\">\n <span>富文本:</span>\n </div>\n <div style=\"flex: 1;\">\n <TinyMceEditor v-model:model-value=\"richText\" v-bind=\"attrs\" style=\"width: 100%;\" />\n <div class=\"flex flex-justify-end\">\n <el-link\n type=\"danger\"\n @click=\"deleteRichText\"\n >\n 删除富文本\n </el-link>\n </div>\n </div>\n </div>\n </template>\n <SubjectAction\n v-if=\"showAction\"\n :is-edit=\"isEdit\"\n :is-set=\"isSet\"\n :isKey=\"isKey\"\n :examAnswerRelationType=\"props.examAnswerRelationType\"\n :answerCheckType=\"answerCheckType\"\n @move-up=\"emits('move', 'up')\"\n @move-down=\"emits('move', 'down')\"\n @delete=\"emits('delete')\"\n @save=\"save\"\n @edit=\"emits('edit')\"\n @add=\"add\"\n @onShowRichText=\"showRichText = true\"\n @setKey=\"setKey\"\n @setAnswerSetting=\"setAnswerSetting\"\n />\n </SubjectLayout>\n <el-dialog\n v-model=\"showRichContent\"\n title=\"添加结果\"\n class=\"customize-dialog\"\n >\n <TinyMceEditor\n :key=\"answersIndex\"\n v-model:model-value=\"resultItem\" \n v-bind=\"attrs\"\n style=\"width: 100%;\" />\n <template #footer>\n <el-button\n class=\"customize-button\"\n type=\"primary\"\n plain\n @click=\"onCloseResult\"\n >\n 取消\n </el-button>\n <el-button\n class=\"customize-button\"\n type=\"primary\"\n plain\n @click=\"onSaveResult\"\n >\n 保存\n </el-button>\n </template>\n </el-dialog>\n </div>\n</template>\n"],"names":["props","__props","emits","__emit","attrs","useAttrs","answersIndex","ref","isKey","answerCheckType","examAnswerRelationType","answers","title","isCorrect","leastAnswerCount","analysis","showRichText","richText","startTime","showRichContent","resultItem","titlePlaceholder","computed","type","orderList","leastAnswerOptions","items","count","value","length","push","label","reverse","addAnswer","isSave","customAnswerId","setGuid","deleteRichText","save","ElMessage","error","msg","isSetCorrectAnswer","correctAnswerCount","forEach","v","i","String","fromCharCode","Set","map","item","size","console","log","index","orderIndex","examExpand","charCodeAt","join","examRichTextContent","onSaveResult","onCloseResult","setKey","key","setAnswerSetting","add","canSet","watch","isEdit","Date","getTime","relationLength","relationAnswers","ns","useNamespace","onMounted","answerList","correctAnswerIdList","split","id","answer","find","answerId","toString","filter","Boolean","it","event","splice","examAnswerId","customId"],"mappings":"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"}
|
1
|
+
{"version":3,"file":"subject-single.vue.mjs","sources":["../../../../../../../packages/components/src/subject-list/src/components/subject-single.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { CirclePlus, Remove } from '@element-plus/icons-vue'\nimport { useNamespace } from '@qxs-bns/hooks'\nimport SubjectAction from '../../../subject-action/src/subject-action.vue'\nimport SubjectLayout from '../../../subject-layout/src/subject-layout.vue'\nimport TinyMceEditor from '../../../tiny-mce-editor/src/tiny-mce-editor.vue'\nimport { setGuid } from '@qxs-bns/utils'\n\ndefineOptions({\n name: 'QxsSubjectSingle',\n})\nconst props = defineProps<{\n orderIndex: number\n title?: string\n isSave: boolean\n showAction?: boolean\n type: 'single' | 'multiple' | 'sort'\n isEdit: boolean\n isSet: boolean\n answerList?: any\n leastAnswerCount?: number\n analysis?: string\n examExpand?: string\n examRichTextContent?: string\n showAnalysis?: boolean\n examAnswerRelationType?: number\n customId?: number\n examId?: number\n isKey: boolean\n answerCheckType: number\n}>()\nconst emits = defineEmits(['move', 'save', 'delete', 'edit', 'add', 'setRelation'])\n\nconst attrs = useAttrs()\n\nconst answersIndex = ref(0)\nconst isKey = ref(props.isKey)\nconst answerCheckType = ref(1)\nconst examAnswerRelationType = ref(1)\nconst answers = ref<{\n title: string\n isCorrect: boolean\n orderIndex?: number\n resultItem?: string\n customAnswerId?: string\n answerRelations?: {\n relationExamId: number\n relationAnswers: {\n relationAnswerId: number\n relationAnswerIndex: number\n }[]\n }[]\n}[]>([{\n title: '',\n isCorrect: false,\n}, {\n title: '',\n isCorrect: false,\n}, {\n title: '',\n isCorrect: false,\n}, {\n title: '',\n isCorrect: false,\n}])\n\nconst leastAnswerCount = ref(2)\nconst title = ref('')\nconst analysis = ref('')\nconst showRichText = ref(false)\nconst richText = ref('')\nconst startTime = ref(0)\nconst showRichContent = ref(false)\nconst resultItem = ref<string>('')\nconst titlePlaceholder = computed(() => {\n if (props.type === 'single') {\n return '单选题'\n }\n else if (props.type === 'multiple') {\n return '多选题'\n }\n else {\n return '排序题'\n }\n})\n\nconst orderList = ref<string[]>([])\n\nconst leastAnswerOptions = computed(() => {\n const items = []\n const length = answers.value.length\n for (let count = length; count > 1; count--) {\n items.push({\n label: `至少选择${count}项`,\n value: count,\n })\n }\n return items.reverse()\n})\nfunction addAnswer() {\n if (props.isSave) {\n return\n }\n answers.value.push({\n title: '',\n isCorrect: false,\n customAnswerId: setGuid()\n })\n}\n\nfunction deleteAnswer(index: number) {\n if (answers.value.length < 3 || props.isSave) {\n return\n }\n answers.value.splice(index, 1)\n}\n\nfunction setCorrect(it: any, event: any) {\n if (props.type === 'single') {\n // 单选题:确保只有一个支持选项\n if (event) {\n answers.value.forEach((answer: any) => {\n if (answer !== it) {\n answer.isCorrect = false\n }\n })\n }\n it.isCorrect = event\n } else if (props.type === 'multiple') {\n // 多选题:可以有多个支持选项\n it.isCorrect = event\n }\n}\nfunction setRelation(item: any) {\n item.customAnswerId = item.examAnswerId || setGuid()\n emits('setRelation', props.customId, item)\n}\n\nfunction deleteRichText() {\n showRichText.value = false\n richText.value = ''\n}\n\nfunction save() {\n if (!title.value) {\n ElMessage.error('题目标题不能为空!')\n return\n }\n let msg = ''\n let isSetCorrectAnswer = false\n // let examAnswerRelationType = null\n let correctAnswerCount = 0\n if (props.type === 'multiple' || props.type === 'single') {\n answers.value.forEach((v: any, i: number) => {\n if (!v.title?.trim()) {\n msg += `选项${String.fromCharCode(65 + i)}未填写。`\n }\n if (v.isCorrect) {\n isSetCorrectAnswer = true\n correctAnswerCount++\n }\n v.relationType = v.resultItem ? 1 : (v.answerRelations?.length ? 2 : null)\n })\n }\n else if (props.type === 'sort') {\n // 如果设置了支持选项\n if (orderList.value.length) {\n isSetCorrectAnswer = true\n }\n }\n if (msg) {\n ElMessage.error(msg)\n return\n }\n\n const uniqueAnswer = new Set(answers.value.map((item: any) => item.title))\n\n if (uniqueAnswer.size !== answers.value.length) {\n ElMessage.error('选项不能重复')\n return\n }\n\n if (props.type === 'multiple') {\n if (correctAnswerCount === 1) {\n ElMessage.error('请至少设置两个支持选项')\n return\n }\n\n if (isSetCorrectAnswer && correctAnswerCount < leastAnswerCount.value) {\n ElMessage.error('至少选几项与支持选项数不符')\n return\n }\n } \n\n if(answerCheckType.value === 2 || answerCheckType.value === 3) {\n // 必须有设置支持选项\n if (!isSetCorrectAnswer) {\n ElMessage.error('请设置支持选项')\n return\n }\n }\n\n emits('save', {\n title: title.value,\n answers: answers.value.map((item: any, index: number) => {\n return { ...item, orderIndex: index + 1 }\n }),\n examExpand: orderList.value.map((i: string) => i.charCodeAt(0) - 65 + 1).join(','),\n analysis: analysis.value,\n isSetCorrectAnswer,\n leastAnswerCount: leastAnswerCount.value,\n examRichTextContent: showRichText.value ? richText.value : '',\n examAnswerRelationType: examAnswerRelationType.value,\n isKey: isKey.value,\n answerCheckType: answerCheckType.value\n })\n}\n\nfunction init() {\n if (props.title) {\n title.value = props.title\n }\n // const customId = props.id || setGuid()\n\n if (props.answerCheckType) {\n answerCheckType.value = props.answerCheckType\n }\n // if (props.isKey) {\n // isKey.value = props.isKey\n // }\n\n if (props.examAnswerRelationType) {\n examAnswerRelationType.value = props.examAnswerRelationType\n }\n\n if (props.answerList && props.answerList.length) {\n answers.value = props.answerList\n }\n\n if (props.leastAnswerCount) {\n leastAnswerCount.value = props.leastAnswerCount\n }\n\n if (props.examExpand) {\n // 设置支持选项 props.examExpand里是答案id\n if (props.examExpand) {\n const correctAnswerIdList = props.examExpand.split(',')\n\n // 遍历 correctAnswerIdList,直接在 props.answerList 中查找对应的 orderIndex 并转换成字母\n orderList.value = correctAnswerIdList.map((id: string) => {\n const answer = props.answerList.find((item: any) => item.answerId?.toString() === id)\n return answer ? String.fromCharCode(65 + answer.orderIndex - 1) : id\n }).filter(Boolean) // 过滤掉任何可能的空字符串\n }\n }\n\n if (props.analysis) {\n analysis.value = props.analysis\n }\n\n if (props.examRichTextContent) {\n richText.value = props.examRichTextContent\n showRichText.value = true\n }\n}\nfunction onOpenResult(i: number) {\n answersIndex.value = i\n resultItem.value = answers.value[i].resultItem || ''\n showRichContent.value = true\n}\n\nfunction onSaveResult() {\n answers.value[answersIndex.value].resultItem = resultItem.value || ''\n showRichContent.value = false\n}\nfunction onCloseResult() {\n showRichContent.value = false\n resultItem.value = ''\n}\nfunction setKey(key: boolean) {\n isKey.value = key\n}\nfunction setAnswerSetting(type: number) {\n answerCheckType.value = type\n}\n\nfunction add(type: string, canSet: boolean) {\n emits('add', type, canSet? props.examAnswerRelationType: null)\n}\n// 监听isEdit\nwatch(() => props.isEdit, () => {\n if (props.isEdit) {\n startTime.value = new Date().getTime()\n }\n})\n\nconst relationLength = computed(() => {\n return (v: any) => {\n let count = 0\n v.forEach((item: any) => {\n if (item.relationAnswers) {\n count += item.relationAnswers.length\n }\n })\n return count\n }\n})\n\nconst ns = useNamespace('subject-single')\n\nonMounted(init)\n</script>\n\n<template>\n <div :class=\"ns.e('single-exam')\">\n <SubjectLayout\n :show-edit=\"isEdit\"\n >\n <template #preview>\n <div class=\"preview\">\n <div>\n <span class=\"title\">\n {{ orderIndex + 1 }}.{{ title }}\n <span v-if=\"type === 'single'\">(单选题)</span>\n <span v-else-if=\"['multiple', 'sort'].includes(type)\">\n ({{ titlePlaceholder }}{{ leastAnswerCount ? `至少选${leastAnswerCount}项${type === 'sort' ? '并排序' : ''}` : '' }})\n </span>\n </span>\n </div>\n <div v-if=\"showRichText\">\n <div v-html=\"richText\" />\n </div>\n <div class=\"preview-answer\">\n <template v-if=\"type === 'sort'\">\n <el-checkbox\n v-for=\"(item, index) in answers\"\n :key=\"index\"\n class=\"radio\"\n :disabled=\"true\"\n >\n <span class=\"order\">\n {{ String.fromCharCode(65 + index) }}.\n </span>\n {{ item.title }}\n </el-checkbox>\n </template>\n <template v-else>\n <el-radio\n v-for=\"(item, index) in answers\"\n :key=\"index\"\n class=\"radio\"\n value=\"disabled\"\n disabled\n >\n <span class=\"order\">\n {{ String.fromCharCode(65 + index) }}.\n </span>\n {{ item.title }} \n {{ item.isCorrect ? '(支持选项)' : '' }} \n {{ examAnswerRelationType === 1 ? (item.resultItem? '(已设置结果项)' : '(未设置结果项)' ) : ''}} \n {{ examAnswerRelationType === 2 ? (item.answerRelations?.length? '(已设置关联)' : '(未设置关联)') : '' }}\n </el-radio>\n </template>\n </div>\n </div>\n </template>\n <template v-if=\"isEdit\" #edit>\n <div class=\"flex\" :class=\"[{ 'margin-bottom': showRichText }]\">\n <div class=\"label flex flex-justify-center\">\n <span>题目:</span>\n </div>\n <div style=\"flex: 1;\">\n <el-input\n v-model=\"title\"\n type=\"textarea\"\n :rows=\"2\"\n :placeholder=\"`【${titlePlaceholder}】请输入问题`\"\n :disabled=\"isSave\"\n show-word-limit\n maxlength=\"200\"\n class=\"margin-bottom\"\n />\n </div>\n </div>\n <div class=\"margin-bottom flex flex-items-center\">\n <div class=\"label flex flex-justify-center\">\n <span>设置:</span>\n </div>\n <el-select\n v-if=\"['multiple', 'sort'].includes(type)\"\n v-model=\"leastAnswerCount\"\n style=\"width: 150px;\"\n placeholder=\"至少选择几项\"\n :disabled=\"isSave\"\n >\n <el-option\n v-for=\"item in leastAnswerOptions\"\n :key=\"item.value\"\n :value=\"item.value\"\n :label=\"item.label\"\n >\n </el-option>\n </el-select>\n </div>\n <div class=\"margin-bottom answer-list\">\n <div\n v-for=\"(item, index) in answers\"\n :key=\"index\"\n class=\"answer-item flex flex-items-center\"\n >\n <span class=\"order\">{{ String.fromCharCode(65 + index) }}.</span>\n <el-input\n v-model=\"item.title\"\n class=\"input\"\n show-word-limit\n maxlength=\"100\"\n :placeholder=\"`选项${String.fromCharCode(65 + index)}`\"\n :disabled=\"isSave\"\n />\n <el-checkbox\n v-if=\"['single', 'multiple'].includes(type)\"\n v-model=\"item.isCorrect\"\n :class=\"[{ 'is-correct': item.isCorrect }]\"\n :disabled=\"isSave\"\n style=\"margin-left: 10px;\"\n @change=\"(event: any) => setCorrect(item, event)\"\n >\n 支持选项 \n </el-checkbox>\n <el-icon class=\"icon\">\n <CirclePlus\n :class=\"[{ disabled: isSave }]\"\n @click=\"addAnswer\"\n />\n </el-icon>\n <el-icon class=\"icon\">\n <Remove\n :class=\"[{ disabled: answers.length < 3 || isSave }]\"\n @click=\"deleteAnswer(index)\"\n />\n </el-icon>\n <el-link\n v-if=\"examAnswerRelationType === 1\"\n type=\"primary\"\n class=\"margin-left-10\"\n @click=\"onOpenResult(index)\"\n >\n <span>{{ item.resultItem ? '编辑结果' : '添加结果' }}</span>\n </el-link>\n <el-link\n v-if=\"examAnswerRelationType === 2\"\n type=\"primary\"\n class=\"margin-left-10\"\n @click=\"setRelation(item)\"\n >\n <span>{{ item.answerRelations?.length ? `关联了${relationLength(item.answerRelations)}项` : '关联检查' }}</span>\n </el-link>\n </div>\n </div>\n <div v-if=\"type === 'sort'\" class=\"margin-bottom flex flex-items-center\">\n <div class=\"label flex flex-justify-end\">\n <span>排序答案:</span>\n </div>\n <div style=\"flex: 1;\">\n <el-select\n v-model=\"orderList\"\n mode=\"multiple\"\n style=\"width: 360px;\"\n placeholder=\"请按顺序选择排序答案\"\n :show-arrow=\"true\"\n >\n <!-- :options=\"[...Array(answers.length)].map((_, i) => ({ value: String.fromCharCode(65 + i) }))\" -->\n <el-option\n v-for=\"(item, index) in answers\"\n :key=\"index\"\n :label=\"item.title\"\n :value=\"String.fromCharCode(65 + index)\"\n />\n </el-select>\n </div>\n </div>\n <div\n v-if=\"showAnalysis\"\n class=\"flex\"\n >\n <div class=\"label flex flex-justify-center\">\n <span>解析:</span>\n </div>\n <div style=\"flex: 1;\">\n <el-input\n v-model=\"analysis\"\n type=\"textarea\"\n :rows=\"2\"\n placeholder=\"请输入题目解析\"\n />\n </div>\n </div>\n <div v-if=\"showRichText\" class=\"margin-bottom flex\">\n <div class=\"label flex flex-justify-center\">\n <span>富文本:</span>\n </div>\n <div style=\"flex: 1;\">\n <TinyMceEditor v-model:model-value=\"richText\" v-bind=\"attrs\" style=\"width: 100%;\" />\n <div class=\"flex flex-justify-end\">\n <el-link\n type=\"danger\"\n @click=\"deleteRichText\"\n >\n 删除富文本\n </el-link>\n </div>\n </div>\n </div>\n </template>\n <SubjectAction\n v-if=\"showAction\"\n :is-edit=\"isEdit\"\n :is-set=\"isSet\"\n :isKey=\"isKey\"\n :examAnswerRelationType=\"props.examAnswerRelationType\"\n :answerCheckType=\"answerCheckType\"\n @move-up=\"emits('move', 'up')\"\n @move-down=\"emits('move', 'down')\"\n @delete=\"emits('delete')\"\n @save=\"save\"\n @edit=\"emits('edit')\"\n @add=\"add\"\n @onShowRichText=\"showRichText = true\"\n @setKey=\"setKey\"\n @setAnswerSetting=\"setAnswerSetting\"\n />\n </SubjectLayout>\n <el-dialog\n v-model=\"showRichContent\"\n title=\"添加结果\"\n class=\"customize-dialog\"\n >\n <TinyMceEditor\n :key=\"answersIndex\"\n v-model:model-value=\"resultItem\" \n v-bind=\"attrs\"\n style=\"width: 100%;\" />\n <template #footer>\n <el-button\n class=\"customize-button\"\n type=\"primary\"\n plain\n @click=\"onCloseResult\"\n >\n 取消\n </el-button>\n <el-button\n class=\"customize-button\"\n type=\"primary\"\n plain\n @click=\"onSaveResult\"\n >\n 保存\n </el-button>\n </template>\n </el-dialog>\n </div>\n</template>\n"],"names":["props","__props","emits","__emit","attrs","useAttrs","answersIndex","ref","isKey","answerCheckType","examAnswerRelationType","answers","title","isCorrect","leastAnswerCount","analysis","showRichText","richText","startTime","showRichContent","resultItem","titlePlaceholder","computed","type","orderList","leastAnswerOptions","items","count","value","length","push","label","reverse","addAnswer","isSave","customAnswerId","setGuid","deleteRichText","save","ElMessage","error","msg","isSetCorrectAnswer","correctAnswerCount","forEach","v","i","trim","String","fromCharCode","relationType","answerRelations","Set","map","item","size","index","orderIndex","examExpand","charCodeAt","join","examRichTextContent","onSaveResult","onCloseResult","setKey","key","setAnswerSetting","add","canSet","watch","isEdit","Date","getTime","relationLength","relationAnswers","ns","useNamespace","onMounted","answerList","correctAnswerIdList","split","id","answer","find","answerId","toString","filter","Boolean","it","event","splice","examAnswerId","customId"],"mappings":"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"}
|
package/lib/package.json.cjs
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
"use strict";exports.version="0.0.
|
1
|
+
"use strict";exports.version="0.0.34";
|
2
2
|
//# sourceMappingURL=package.json.cjs.map
|
@@ -1,2 +1,2 @@
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("vue"),a=require("lodash-es"),t=require("../utils/injectionKeys.cjs"),s=require("../utils/useCharts.cjs"),r=e.defineComponent({name:"DataChartBar",__name:"bar",props:{chartData:{type:Object,required:!0,default:()=>({colDesc:[],xGroupByDesc:{colDesc:"",groupByDesc:"",groupByValues:[],xAxis:!1},groupByDesc:[],data:[],modelName:""})},subShowType:{type:String,required:!0,default:"bar-simple"},chartOptions:{type:null,required:!0}},setup(r){const c=e.inject(t.InjectionChartMerge,(e=>e),!0),
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("vue"),a=require("lodash-es"),t=require("../utils/injectionKeys.cjs"),s=require("../utils/useCharts.cjs"),r=e.defineComponent({name:"DataChartBar",__name:"bar",props:{chartData:{type:Object,required:!0,default:()=>({colDesc:[],xGroupByDesc:{colDesc:"",groupByDesc:"",groupByValues:[],xAxis:!1},groupByDesc:[],data:[],modelName:""})},subShowType:{type:String,required:!0,default:"bar-simple"},chartOptions:{type:null,required:!0}},setup(r){const c=e.inject(t.InjectionChartMerge,(e=>e),!0),l=e.ref(null),o=e.computed((()=>{const{colDesc:e,xGroupByDesc:t,groupByDesc:s,data:l=[],modelName:o}=r.chartData,i=Array.from(new Set(l.map((e=>e[t.colDesc||""])))).filter((e=>null!=e))||[],u=s.find((e=>!e.xAxis))||{groupByValues:[],colDesc:""};u.groupByValues=a.uniq(l.map((e=>u.colDesc?String(e[u.colDesc]):""))),t&&t.groupByValues&&(t.groupByValues=a.uniq(l.map((e=>t.colDesc?String(e[t.colDesc]):""))));const n={title:{text:o},xAxis:{name:"",type:"category",axisLabel:{interval:0,formatter:e=>e.length>5?`${e.substring(0,5)}...`:e},data:i},yAxis:{type:"value"},legend:{data:[]},dataZoom:[{type:"inside",disabled:i.length<15}]};if(1===s.length)n.series=e.map((e=>({name:e,data:l.map((a=>a[e])),type:"bar",emphasis:{focus:"series"},label:{show:!0,position:"inside"}}))),n.legend.data=e;else if(2===s.length){const a=e.map((e=>u.groupByValues?.map((a=>{const s={name:`${a||"/"}-${e}`,type:"bar",stack:e,emphasis:{focus:"series"},data:[],label:{show:!0,position:"inside"}};return s.data=(t.groupByValues||[]).map((e=>{let r=null;return l.forEach((c=>{u.colDesc&&c[u.colDesc]===a&&t.colDesc&&c[t.colDesc]===e&&s.stack&&(r=c[s.stack]??null)})),r||""})).filter((e=>""!==e)),s}))||[])).flat();n.series=a,delete n.legend}function p(e,a,t,s){Array.isArray(e)?e.forEach((e=>{e&&(e.type=a,"category"===a&&(e.data=t||[],e.name=s||""))})):e&&(e.type=a,"category"===a&&(e.data=t||[],e.name=s||""))}switch(r.subShowType){case"bar-simple":case"default":p(n.xAxis,"category",i,t.colDesc||""),p(n.yAxis,"value");break;case"bar-y-category":p(n.xAxis,"value"),p(n.yAxis,"category",i,t.colDesc||"")}return c(n,r.chartOptions)}));return s.useCharts({chartDOM:l,chartOptions:o,chartData:e.computed((()=>r.chartData))}),(a,t)=>(e.openBlock(),e.createElementBlock("div",{ref_key:"dataChartBar",ref:l,class:"data-chart-bar"},null,512))}});exports.default=r;
|
2
2
|
//# sourceMappingURL=bar.vue.cjs.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"bar.vue.cjs","sources":["../../../../../../../packages/components/src/data-chart/src/components/bar.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { LegendComponentOption, XAXisComponentOption, YAXisComponentOption } from 'echarts'\nimport type {\n EChartData,\n EChartsOption,\n IFormatPublicData,\n SeriesOption,\n} from '../types'\nimport { uniq } from 'lodash-es'\nimport { InjectionChartMerge } from '../utils/injectionKeys'\nimport { useCharts } from '../utils/useCharts'\n\n// 定义组件名称\ndefineOptions({\n name: 'DataChartBar',\n})\n\n// 定义组件属性\nconst {\n chartOptions,\n chartData = {\n colDesc: [],\n xGroupByDesc: {\n colDesc: '',\n groupByDesc: '',\n groupByValues: [],\n xAxis: false,\n },\n groupByDesc: [],\n data: [],\n modelName: '',\n },\n subShowType = 'bar-simple',\n} = defineProps<{\n chartData: IFormatPublicData\n subShowType: string\n chartOptions: EChartsOption\n}>()\n\n// 注入合并函数,并明确类型\nconst merge = inject(InjectionChartMerge, (v: any) => v, true) as (config: EChartsOption, chartOptions: EChartsOption) => EChartsOption\nconst dataChartBar = ref<HTMLElement | null>(null)\n\n// 计算图表选项\nconst barChartOptions = computed<EChartsOption>(() => {\n const { colDesc, xGroupByDesc, groupByDesc, data = [], modelName } = chartData\n\n const axisData = Array.from(new Set(data.map(item => item[xGroupByDesc.colDesc || '']))) || []\n const yGroupByDesc: EChartData['desc']['groupByDesc'][0] = groupByDesc.find(item => !item.xAxis) || {\n groupByDesc: null,\n groupByValues: [],\n colDesc: '',\n xAxis: false,\n }\n\n yGroupByDesc.groupByValues = uniq(data.map(item => yGroupByDesc.colDesc ? String(item[yGroupByDesc.colDesc]) : ''))\n if (xGroupByDesc && xGroupByDesc.groupByValues) {\n xGroupByDesc.groupByValues = uniq(data.map(item => xGroupByDesc.colDesc ? String(item[xGroupByDesc.colDesc]) : ''))\n }\n\n const config: EChartsOption = {\n title: {\n text: modelName,\n },\n xAxis: {\n name: '',\n type: 'category',\n axisLabel: {\n interval: 0, // 强制显示所有标签\n formatter(value: string) {\n const screenshotLength = 5\n return value.length > screenshotLength ? `${value.substring(0, screenshotLength)}...` : value // 截取前5个字符并添加省略号\n },\n },\n data: axisData,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: [],\n },\n dataZoom: [{\n type: 'inside',\n disabled: axisData.length < 15,\n }],\n }\n\n // 堆叠图\n if (groupByDesc.length === 1) {\n config.series = colDesc.map((yItem) => {\n return {\n name: yItem,\n data: data.map(item => item[yItem]),\n type: 'bar',\n emphasis: {\n focus: 'series',\n },\n label: {\n show: true,\n position: 'inside',\n },\n }\n });\n (config.legend as LegendComponentOption).data = colDesc\n }\n else if (groupByDesc.length === 2) {\n const arr = colDesc.map((colDescItem) => {\n return yGroupByDesc.groupByValues?.map((yGroupByDescItem) => {\n const obj: SeriesOption = {\n name: `${yGroupByDescItem || '/'}-${colDescItem}`,\n type: 'bar',\n stack: colDescItem,\n emphasis: {\n focus: 'series',\n },\n data: [],\n label: {\n show: true,\n position: 'inside',\n },\n }\n obj.data = (xGroupByDesc.groupByValues || []).map((xGroupByDescItem) => {\n let targetVal: number | string | null = null\n data.forEach((item) => {\n if (yGroupByDesc.colDesc && item[yGroupByDesc.colDesc] === yGroupByDescItem && xGroupByDesc.colDesc && item[xGroupByDesc.colDesc] === xGroupByDescItem) {\n if (obj.stack) {\n targetVal = item[obj.stack] ?? null\n }\n }\n })\n return targetVal || ''\n }).filter(v => v !== '')\n return obj\n }) || []\n }).flat()\n\n config.series = arr\n delete config.legend\n }\n\n // 1. 定义轴类型\n type CategoryAxisOption = XAXisComponentOption & {\n type: 'category'\n data: (string | number)[]\n }\n\n // 2. 创建配置轴的辅助函数\n function configureAxis(\n axis: XAXisComponentOption | XAXisComponentOption[] | YAXisComponentOption | YAXisComponentOption[] | undefined,\n type: 'category' | 'value',\n data?: (string | number)[],\n name?: string,\n ) {\n if (Array.isArray(axis)) {\n axis.forEach((item) => {\n if (item) {\n item.type = type\n if (type === 'category') {\n (item as CategoryAxisOption).data = data || []\n item.name = name || ''\n }\n }\n })\n }\n else if (axis) {\n axis.type = type\n if (type === 'category') {\n (axis as CategoryAxisOption).data = data || []\n axis.name = name || ''\n }\n }\n }\n\n // 3. 使用配置函数\n switch (subShowType) {\n case 'bar-simple':\n case 'default':\n configureAxis(config.xAxis, 'category', axisData, xGroupByDesc.colDesc || '')\n configureAxis(config.yAxis, 'value')\n break\n\n case 'bar-y-category':\n configureAxis(config.xAxis, 'value')\n configureAxis(config.yAxis, 'category', axisData, xGroupByDesc.colDesc || '')\n break\n }\n\n return merge(config, chartOptions)\n})\n\nuseCharts({ chartDOM: dataChartBar, chartOptions: barChartOptions, chartData: computed(() => chartData) })\n</script>\n\n<template>\n <div ref=\"dataChartBar\" class=\"data-chart-bar\" />\n</template>\n"],"names":["merge","inject","InjectionChartMerge","v","dataChartBar","ref","barChartOptions","computed","colDesc","xGroupByDesc","groupByDesc","data","modelName","__props","chartData","axisData","Array","from","Set","map","item","yGroupByDesc","find","xAxis","groupByValues","uniq","String","config","title","text","name","type","axisLabel","interval","formatter","value","length","substring","yAxis","legend","dataZoom","disabled","series","yItem","emphasis","focus","label","show","position","arr","colDescItem","yGroupByDescItem","obj","stack","xGroupByDescItem","targetVal","forEach","
|
1
|
+
{"version":3,"file":"bar.vue.cjs","sources":["../../../../../../../packages/components/src/data-chart/src/components/bar.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { LegendComponentOption, XAXisComponentOption, YAXisComponentOption } from 'echarts'\nimport type {\n EChartData,\n EChartsOption,\n IFormatPublicData,\n SeriesOption,\n} from '../types'\nimport { uniq } from 'lodash-es'\nimport { InjectionChartMerge } from '../utils/injectionKeys'\nimport { useCharts } from '../utils/useCharts'\n\n// 定义组件名称\ndefineOptions({\n name: 'DataChartBar',\n})\n\n// 定义组件属性\nconst {\n chartOptions,\n chartData = {\n colDesc: [],\n xGroupByDesc: {\n colDesc: '',\n groupByDesc: '',\n groupByValues: [],\n xAxis: false,\n },\n groupByDesc: [],\n data: [],\n modelName: '',\n },\n subShowType = 'bar-simple',\n} = defineProps<{\n chartData: IFormatPublicData\n subShowType: string\n chartOptions: EChartsOption\n}>()\n\n// 注入合并函数,并明确类型\nconst merge = inject(InjectionChartMerge, (v: any) => v, true) as (config: EChartsOption, chartOptions: EChartsOption) => EChartsOption\nconst dataChartBar = ref<HTMLElement | null>(null)\n\n// 计算图表选项\nconst barChartOptions = computed<EChartsOption>(() => {\n const { colDesc, xGroupByDesc, groupByDesc, data = [], modelName } = chartData\n\n const axisData = Array.from(new Set(data.map(item => item[xGroupByDesc.colDesc || '']))).filter(item => item !== undefined && item !== null) || []\n const yGroupByDesc: EChartData['desc']['groupByDesc'][0] = groupByDesc.find(item => !item.xAxis) || {\n groupByDesc: null,\n groupByValues: [],\n colDesc: '',\n xAxis: false,\n }\n\n yGroupByDesc.groupByValues = uniq(data.map(item => yGroupByDesc.colDesc ? String(item[yGroupByDesc.colDesc]) : ''))\n if (xGroupByDesc && xGroupByDesc.groupByValues) {\n xGroupByDesc.groupByValues = uniq(data.map(item => xGroupByDesc.colDesc ? String(item[xGroupByDesc.colDesc]) : ''))\n }\n\n const config: EChartsOption = {\n title: {\n text: modelName,\n },\n xAxis: {\n name: '',\n type: 'category',\n axisLabel: {\n interval: 0, // 强制显示所有标签\n formatter(value: string) {\n const screenshotLength = 5\n return value.length > screenshotLength ? `${value.substring(0, screenshotLength)}...` : value // 截取前5个字符并添加省略号\n },\n },\n data: axisData,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: [],\n },\n dataZoom: [{\n type: 'inside',\n disabled: axisData.length < 15,\n }],\n }\n\n // 堆叠图\n if (groupByDesc.length === 1) {\n config.series = colDesc.map((yItem) => {\n return {\n name: yItem,\n data: data.map(item => item[yItem]),\n type: 'bar',\n emphasis: {\n focus: 'series',\n },\n label: {\n show: true,\n position: 'inside',\n },\n }\n });\n (config.legend as LegendComponentOption).data = colDesc\n }\n else if (groupByDesc.length === 2) {\n const arr = colDesc.map((colDescItem) => {\n return yGroupByDesc.groupByValues?.map((yGroupByDescItem) => {\n const obj: SeriesOption = {\n name: `${yGroupByDescItem || '/'}-${colDescItem}`,\n type: 'bar',\n stack: colDescItem,\n emphasis: {\n focus: 'series',\n },\n data: [],\n label: {\n show: true,\n position: 'inside',\n },\n }\n obj.data = (xGroupByDesc.groupByValues || []).map((xGroupByDescItem) => {\n let targetVal: number | string | null = null\n data.forEach((item) => {\n if (yGroupByDesc.colDesc && item[yGroupByDesc.colDesc] === yGroupByDescItem && xGroupByDesc.colDesc && item[xGroupByDesc.colDesc] === xGroupByDescItem) {\n if (obj.stack) {\n targetVal = item[obj.stack] ?? null\n }\n }\n })\n return targetVal || ''\n }).filter(v => v !== '')\n return obj\n }) || []\n }).flat()\n\n config.series = arr\n delete config.legend\n }\n\n // 1. 定义轴类型\n type CategoryAxisOption = XAXisComponentOption & {\n type: 'category'\n data: (string | number)[]\n }\n\n // 2. 创建配置轴的辅助函数\n function configureAxis(\n axis: XAXisComponentOption | XAXisComponentOption[] | YAXisComponentOption | YAXisComponentOption[] | undefined,\n type: 'category' | 'value',\n data?: (string | number)[],\n name?: string,\n ) {\n if (Array.isArray(axis)) {\n axis.forEach((item) => {\n if (item) {\n item.type = type\n if (type === 'category') {\n (item as CategoryAxisOption).data = data || []\n item.name = name || ''\n }\n }\n })\n }\n else if (axis) {\n axis.type = type\n if (type === 'category') {\n (axis as CategoryAxisOption).data = data || []\n axis.name = name || ''\n }\n }\n }\n\n // 3. 使用配置函数\n switch (subShowType) {\n case 'bar-simple':\n case 'default':\n configureAxis(config.xAxis, 'category', axisData, xGroupByDesc.colDesc || '')\n configureAxis(config.yAxis, 'value')\n break\n\n case 'bar-y-category':\n configureAxis(config.xAxis, 'value')\n configureAxis(config.yAxis, 'category', axisData, xGroupByDesc.colDesc || '')\n break\n }\n\n return merge(config, chartOptions)\n})\n\nuseCharts({ chartDOM: dataChartBar, chartOptions: barChartOptions, chartData: computed(() => chartData) })\n</script>\n\n<template>\n <div ref=\"dataChartBar\" class=\"data-chart-bar\" />\n</template>\n"],"names":["merge","inject","InjectionChartMerge","v","dataChartBar","ref","barChartOptions","computed","colDesc","xGroupByDesc","groupByDesc","data","modelName","__props","chartData","axisData","Array","from","Set","map","item","filter","yGroupByDesc","find","xAxis","groupByValues","uniq","String","config","title","text","name","type","axisLabel","interval","formatter","value","length","substring","yAxis","legend","dataZoom","disabled","series","yItem","emphasis","focus","label","show","position","arr","colDescItem","yGroupByDescItem","obj","stack","xGroupByDescItem","targetVal","forEach","flat","configureAxis","axis","isArray","subShowType","chartOptions","useCharts","chartDOM"],"mappings":"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"}
|
@@ -1,2 +1,2 @@
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("vue"),t=require("../utils/injectionKeys.cjs"),a=require("../utils/useCharts.cjs"),r=e.defineComponent({name:"DataChartLine",__name:"line",props:{chartData:{type:Object,required:!0,default:()=>({colDesc:[],xGroupByDesc:{colDesc:"",groupByDesc:"",groupByValues:[],xAxis:!1},groupByDesc:[],data:[],modelName:""})},subShowType:{type:String,required:!0,default:"line-simple"},chartOptions:{type:null,required:!0}},setup(r){const s=e.ref(),c=e.inject(t.InjectionChartMerge,(e=>e),!0),n=15,
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("vue"),t=require("../utils/injectionKeys.cjs"),a=require("../utils/useCharts.cjs"),r=e.defineComponent({name:"DataChartLine",__name:"line",props:{chartData:{type:Object,required:!0,default:()=>({colDesc:[],xGroupByDesc:{colDesc:"",groupByDesc:"",groupByValues:[],xAxis:!1},groupByDesc:[],data:[],modelName:""})},subShowType:{type:String,required:!0,default:"line-simple"},chartOptions:{type:null,required:!0}},setup(r){const s=e.ref(),c=e.inject(t.InjectionChartMerge,(e=>e),!0),n=15,l="Total";const i=e.computed((()=>{const{colDesc:e,xGroupByDesc:t,groupByDesc:a,data:s,modelName:i}=r.chartData,o=Array.from(new Set(s?.map((e=>e[t?.colDesc||""])))).filter((e=>null!=e))||[],u=a?.find((e=>!e.xAxis)),p={title:{text:i},legend:{data:[]},xAxis:{name:t?.colDesc||"",data:o},dataZoom:[{type:"inside",disabled:o.length<n}]};if(1===a?.length)p.series=e.map((e=>({name:e,type:"line",data:s.map((t=>t[e])).filter((e=>null!=e))}))),p.legend.data=e;else if(2===a?.length){const a=[...new Set(s.map((e=>String(e[u?.colDesc||""]))))];p.legend.data=a,p.series=a.map((a=>function(e,t,a,r,s,c){const n=[];return t.forEach((t=>{const l=a.find((a=>a[r?.colDesc]===t&&a[s?.colDesc]===e));l?n.push(l[c[0]]):n.push(0)})),{name:e,type:"line",stack:l,areaStyle:{},data:n}}(a,o,s,t,u,e)))}return p.series=p.series?.map((e=>{const t={...e};switch(r.subShowType){case"line-simple":default:delete t.areaStyle;break;case"area-basic":t.areaStyle={}}return t})),c(p,r.chartOptions)}));return a.useCharts({chartDOM:s,chartOptions:i,chartData:e.computed((()=>r.chartData))}),(t,a)=>(e.openBlock(),e.createElementBlock("div",{ref_key:"dataChartLine",ref:s,class:"data-chart-line"},null,512))}});exports.default=r;
|
2
2
|
//# sourceMappingURL=line.vue2.cjs.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"line.vue2.cjs","sources":["../../../../../../../packages/components/src/data-chart/src/components/line.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { LegendComponentOption } from 'echarts'\nimport type { EChartsOption, IFormatPublicData } from '../types'\nimport { InjectionChartMerge } from '../utils/injectionKeys'\nimport { useCharts } from '../utils/useCharts'\n\ndefineOptions({\n name: 'DataChartLine',\n})\nconst {\n chartData = {\n colDesc: [],\n xGroupByDesc: {\n colDesc: '',\n groupByDesc: '',\n groupByValues: [],\n xAxis: false,\n },\n groupByDesc: [],\n data: [],\n modelName: '',\n },\n subShowType = 'line-simple',\n chartOptions,\n} = defineProps<{\n chartData: IFormatPublicData\n subShowType: string\n chartOptions: EChartsOption\n}>()\nconst dataChartLine = ref()\nconst merge = inject(InjectionChartMerge, (v: any) => v, true)\n\n// 抽取类型定义\ninterface SeriesItem {\n name: string\n type: 'line'\n stack?: string\n areaStyle?: Record<string, any>\n data: Array<string | number>\n}\n\n// 将配置提取为常量\nconst CHART_CONSTANTS = {\n MIN_ZOOM_LENGTH: 15,\n STACK_NAME: 'Total',\n} as const\n\n// 提取处理图表系列数据的函数\nfunction processSeriesData(legendDataItem: string,\n xAxisData: (string | number)[],\n data: any[],\n xGroupByDesc: any,\n yGroupByDesc: any,\n colDesc: string[]): SeriesItem {\n const seriesData: (string | number)[] = []\n\n xAxisData.forEach((xAxisItem) => {\n const targetData = data\n .find(dataItem =>\n dataItem[xGroupByDesc?.colDesc] === xAxisItem\n && dataItem[yGroupByDesc?.colDesc] === legendDataItem,\n )\n\n if (targetData) {\n seriesData.push(targetData[colDesc[0]])\n }\n else {\n seriesData.push(0) // 或者其他默认值\n }\n })\n\n return {\n name: legendDataItem,\n type: 'line',\n stack: CHART_CONSTANTS.STACK_NAME,\n areaStyle: {},\n data: seriesData,\n }\n}\n\nconst lineChartOptions = computed<EChartsOption>(() => {\n const { colDesc, xGroupByDesc, groupByDesc, data, modelName } = chartData\n const xAxisData = Array.from(new Set(data?.map(item => item[xGroupByDesc?.colDesc || '']))) || []\n const yGroupByDesc = groupByDesc?.find(item => !item.xAxis)\n\n const config: EChartsOption & { series?: SeriesItem[] } = {\n title: { text: modelName },\n legend: { data: [] },\n xAxis: {\n name: xGroupByDesc?.colDesc || '',\n data: xAxisData,\n },\n dataZoom: [{\n type: 'inside',\n disabled: xAxisData.length < CHART_CONSTANTS.MIN_ZOOM_LENGTH,\n }],\n }\n\n // 处理系列数据\n if (groupByDesc?.length === 1) {\n config.series = colDesc.map(yItem => ({\n name: yItem,\n type: 'line',\n data: data.map(item => item[yItem]),\n }));\n (config.legend as LegendComponentOption).data = colDesc\n }\n else if (groupByDesc?.length === 2) {\n const legendData = [...new Set(data.map(item => String(item[yGroupByDesc?.colDesc || ''])))]\n ;(config.legend as LegendComponentOption).data = legendData\n\n config.series = legendData.map(legendDataItem =>\n processSeriesData(legendDataItem, xAxisData, data, xGroupByDesc, yGroupByDesc, colDesc),\n )\n }\n\n // 处理图表展示类型\n config.series = config.series?.map((item) => {\n const seriesItem = { ...item }\n\n switch (subShowType) {\n case 'line-simple':\n delete seriesItem.areaStyle\n break\n case 'area-basic':\n seriesItem.areaStyle = {}\n break\n default:\n delete seriesItem.areaStyle\n }\n\n return seriesItem\n })\n\n return merge(config, chartOptions)\n})\nuseCharts({ chartDOM: dataChartLine, chartOptions: lineChartOptions, chartData: computed(() => chartData) })\n</script>\n\n<template>\n <div ref=\"dataChartLine\" class=\"data-chart-line\" />\n</template>\n\n<style scoped lang=\"scss\">\n.data-chart-line {\n width: 100%;\n height: 100%;\n}\n</style>\n"],"names":["dataChartLine","ref","merge","inject","InjectionChartMerge","v","CHART_CONSTANTS","lineChartOptions","computed","colDesc","xGroupByDesc","groupByDesc","data","modelName","__props","chartData","xAxisData","Array","from","Set","map","item","yGroupByDesc","find","xAxis","config","title","text","legend","name","dataZoom","type","disabled","length","series","yItem","legendData","String","legendDataItem","seriesData","forEach","xAxisItem","targetData","dataItem","push","stack","areaStyle","processSeriesData","seriesItem","subShowType","chartOptions","useCharts","chartDOM"],"mappings":"qfA6BA,MAAMA,EAAgBC,EAAAA,MAChBC,EAAQC,EAAAA,OAAOC,EAAAA,qBAAsBC,GAAWA,IAAG,GAYnDC,EACa,GADbA,EAEQ,QAoCR,MAAAC,EAAmBC,EAAAA,UAAwB,KAC/C,MAAMC,QAAEA,EAASC,aAAAA,EAAAC,YAAcA,OAAaC,EAAMC,UAAAA,GAAcC,EAAAC,UAC1DC,EAAYC,MAAMC,KAAK,IAAIC,IAAIP,GAAMQ,
|
1
|
+
{"version":3,"file":"line.vue2.cjs","sources":["../../../../../../../packages/components/src/data-chart/src/components/line.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { LegendComponentOption } from 'echarts'\nimport type { EChartsOption, IFormatPublicData } from '../types'\nimport { InjectionChartMerge } from '../utils/injectionKeys'\nimport { useCharts } from '../utils/useCharts'\n\ndefineOptions({\n name: 'DataChartLine',\n})\nconst {\n chartData = {\n colDesc: [],\n xGroupByDesc: {\n colDesc: '',\n groupByDesc: '',\n groupByValues: [],\n xAxis: false,\n },\n groupByDesc: [],\n data: [],\n modelName: '',\n },\n subShowType = 'line-simple',\n chartOptions,\n} = defineProps<{\n chartData: IFormatPublicData\n subShowType: string\n chartOptions: EChartsOption\n}>()\nconst dataChartLine = ref()\nconst merge = inject(InjectionChartMerge, (v: any) => v, true)\n\n// 抽取类型定义\ninterface SeriesItem {\n name: string\n type: 'line'\n stack?: string\n areaStyle?: Record<string, any>\n data: Array<string | number>\n}\n\n// 将配置提取为常量\nconst CHART_CONSTANTS = {\n MIN_ZOOM_LENGTH: 15,\n STACK_NAME: 'Total',\n} as const\n\n// 提取处理图表系列数据的函数\nfunction processSeriesData(legendDataItem: string,\n xAxisData: (string | number)[],\n data: any[],\n xGroupByDesc: any,\n yGroupByDesc: any,\n colDesc: string[]): SeriesItem {\n const seriesData: (string | number)[] = []\n\n xAxisData.forEach((xAxisItem) => {\n const targetData = data\n .find(dataItem =>\n dataItem[xGroupByDesc?.colDesc] === xAxisItem\n && dataItem[yGroupByDesc?.colDesc] === legendDataItem,\n )\n\n if (targetData) {\n seriesData.push(targetData[colDesc[0]])\n }\n else {\n seriesData.push(0) // 或者其他默认值\n }\n })\n\n return {\n name: legendDataItem,\n type: 'line',\n stack: CHART_CONSTANTS.STACK_NAME,\n areaStyle: {},\n data: seriesData,\n }\n}\n\nconst lineChartOptions = computed<EChartsOption>(() => {\n const { colDesc, xGroupByDesc, groupByDesc, data, modelName } = chartData\n const xAxisData = Array.from(new Set(data?.map(item => item[xGroupByDesc?.colDesc || '']))).filter(item => item !== undefined && item !== null ) || []\n const yGroupByDesc = groupByDesc?.find(item => !item.xAxis)\n\n const config: EChartsOption & { series?: SeriesItem[] } = {\n title: { text: modelName },\n legend: { data: [] },\n xAxis: {\n name: xGroupByDesc?.colDesc || '',\n data: xAxisData,\n },\n dataZoom: [{\n type: 'inside',\n disabled: xAxisData.length < CHART_CONSTANTS.MIN_ZOOM_LENGTH,\n }],\n }\n\n // 处理系列数据\n if (groupByDesc?.length === 1) {\n config.series = colDesc.map(yItem => ({\n name: yItem,\n type: 'line',\n data: data.map(item => item[yItem]).filter(item => item !== undefined && item !== null),\n }));\n (config.legend as LegendComponentOption).data = colDesc\n }\n else if (groupByDesc?.length === 2) {\n const legendData = [...new Set(data.map(item => String(item[yGroupByDesc?.colDesc || ''])))]\n ;(config.legend as LegendComponentOption).data = legendData\n\n config.series = legendData.map(legendDataItem =>\n processSeriesData(legendDataItem, xAxisData, data, xGroupByDesc, yGroupByDesc, colDesc),\n )\n }\n\n // 处理图表展示类型\n config.series = config.series?.map((item) => {\n const seriesItem = { ...item }\n\n switch (subShowType) {\n case 'line-simple':\n delete seriesItem.areaStyle\n break\n case 'area-basic':\n seriesItem.areaStyle = {}\n break\n default:\n delete seriesItem.areaStyle\n }\n\n return seriesItem\n })\n\n return merge(config, chartOptions)\n})\nuseCharts({ chartDOM: dataChartLine, chartOptions: lineChartOptions, chartData: computed(() => chartData) })\n</script>\n\n<template>\n <div ref=\"dataChartLine\" class=\"data-chart-line\" />\n</template>\n\n<style scoped lang=\"scss\">\n.data-chart-line {\n width: 100%;\n height: 100%;\n}\n</style>\n"],"names":["dataChartLine","ref","merge","inject","InjectionChartMerge","v","CHART_CONSTANTS","lineChartOptions","computed","colDesc","xGroupByDesc","groupByDesc","data","modelName","__props","chartData","xAxisData","Array","from","Set","map","item","filter","yGroupByDesc","find","xAxis","config","title","text","legend","name","dataZoom","type","disabled","length","series","yItem","legendData","String","legendDataItem","seriesData","forEach","xAxisItem","targetData","dataItem","push","stack","areaStyle","processSeriesData","seriesItem","subShowType","chartOptions","useCharts","chartDOM"],"mappings":"qfA6BA,MAAMA,EAAgBC,EAAAA,MAChBC,EAAQC,EAAAA,OAAOC,EAAAA,qBAAsBC,GAAWA,IAAG,GAYnDC,EACa,GADbA,EAEQ,QAoCR,MAAAC,EAAmBC,EAAAA,UAAwB,KAC/C,MAAMC,QAAEA,EAASC,aAAAA,EAAAC,YAAcA,OAAaC,EAAMC,UAAAA,GAAcC,EAAAC,UAC1DC,EAAYC,MAAMC,KAAK,IAAIC,IAAIP,GAAMQ,KAAYC,GAAAA,EAAKX,GAAcD,SAAW,QAAOa,QAAOD,GAAQA,WAAyC,GAC9IE,EAAeZ,GAAaa,MAAaH,IAACA,EAAKI,QAE/CC,EAAoD,CACxDC,MAAO,CAAEC,KAAMf,GACfgB,OAAQ,CAAEjB,KAAM,IAChBa,MAAO,CACLK,KAAMpB,GAAcD,SAAW,GAC/BG,KAAMI,GAERe,SAAU,CAAC,CACTC,KAAM,SACNC,SAAUjB,EAAUkB,OAAS5B,KAK7B,GAAwB,IAAxBK,GAAauB,OACRR,EAAAS,OAAS1B,EAAQW,KAAcgB,IAAA,CACpCN,KAAMM,EACNJ,KAAM,OACNpB,KAAMA,EAAKQ,KAAIC,GAAQA,EAAKe,KAAQd,QAAOD,GAAQA,cAEpDK,EAAOG,OAAiCjB,KAAOH,OAClD,GACiC,IAAxBE,GAAauB,OAAc,CAClC,MAAMG,EAAa,IAAI,IAAIlB,IAAIP,EAAKQ,KAAIC,GAAQiB,OAAOjB,EAAKE,GAAcd,SAAW,SACnFiB,EAAOG,OAAiCjB,KAAOyB,EAEjDX,EAAOS,OAASE,EAAWjB,QA/D/B,SAA2BmB,EACzBvB,EACAJ,EACAF,EACAa,EACAd,GACA,MAAM+B,EAAkC,GAiBjC,OAfGxB,EAAAyB,SAASC,IACjB,MAAMC,EAAa/B,EAChBY,MAAKoB,GACJA,EAASlC,GAAcD,WAAaiC,GACjCE,EAASrB,GAAcd,WAAa8B,IAGvCI,EACFH,EAAWK,KAAKF,EAAWlC,EAAQ,KAGnC+B,EAAWK,KAAK,EAAC,IAId,CACLf,KAAMS,EACNP,KAAM,OACNc,MAAOxC,EACPyC,UAAW,CAAC,EACZnC,KAAM4B,EACR,CAmCIQ,CAAkBT,EAAgBvB,EAAWJ,EAAMF,EAAca,EAAcd,IACjF,CAqBK,OAjBPiB,EAAOS,OAAST,EAAOS,QAAQf,KAAKC,IAC5B,MAAA4B,EAAa,IAAK5B,GAExB,OAAQP,EAAAoC,aACN,IAAK,cAML,eACSD,EAAWF,gBAJpB,IAAK,aACHE,EAAWF,UAAY,CAAC,EAMrB,OAAAE,CAAA,IAGF/C,EAAMwB,EAAQZ,EAAYqC,aAAA,WAEzBC,EAAAA,UAAA,CAAEC,SAAUrD,EAAemD,aAAc5C,EAAkBQ,UAAWP,YAAS,IAAMM,EAAAC"}
|
@@ -1,2 +1,2 @@
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("vue"),t=require("lodash-es"),r=require("../utils/injectionKeys.cjs"),o=require("../utils/useCharts.cjs"),a=e.defineComponent({name:"DataChartPie",__name:"pie",props:{chartData:{type:Object,required:!0,default:()=>({colDesc:[],xGroupByDesc:{colDesc:"",groupByDesc:"",groupByValues:[],xAxis:!1},groupByDesc:[],data:[],modelName:""})},subShowType:{type:String,required:!0,default:"pie-simple"},chartOptions:{type:null,required:!0}},setup(a){const c=e.inject(r.InjectionChartMerge,(e=>e),!0),s=e.ref(null),i=e.computed((()=>{const{colDesc:e,xGroupByDesc:r,data:o,modelName:s}=a.chartData,i=e.length,l={title:{text:s},series:e.map(((e,c)=>{const s={name:e,type:"pie",center:["50%","50%"],data:[],emphasis:{itemStyle:{shadowBlur:10,shadowOffsetX:0,shadowColor:"rgba(0, 0, 0, 0.5)"}},label:{formatter:"{b}:{c}({d}%)",rich:{b:{color:"#4C5058",fontSize:14,fontWeight:"bold",lineHeight:33}}}};let l=5;const n=t.orderBy(t.cloneDeep(o),[e],["desc"]),u=n.reduce(((t,r)=>t+Number(r[e])),0);if(o.length>l)for(;l<9;){const t=n.slice(0,l);if(t.reduce(((t,r)=>t+Number(r[e])),0)/u>.9||8===l){const a=n.slice(l,n.length-1);s.data=o.map((o=>{let a={};return t.forEach((t=>{JSON.stringify(t)===JSON.stringify(o)&&(a={name:r?.colDesc?o[r.colDesc]:"",value:o[e]})})),a})).filter((e=>e)),s.data.push({name:"其它",value:a.reduce(((t,r)=>t+Number(r[e])),0)});break}l++}else s.data=o.map((t=>({name:r?.colDesc
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("vue"),t=require("lodash-es"),r=require("../utils/injectionKeys.cjs"),o=require("../utils/useCharts.cjs"),a=e.defineComponent({name:"DataChartPie",__name:"pie",props:{chartData:{type:Object,required:!0,default:()=>({colDesc:[],xGroupByDesc:{colDesc:"",groupByDesc:"",groupByValues:[],xAxis:!1},groupByDesc:[],data:[],modelName:""})},subShowType:{type:String,required:!0,default:"pie-simple"},chartOptions:{type:null,required:!0}},setup(a){const c=e.inject(r.InjectionChartMerge,(e=>e),!0),s=e.ref(null),i=e.computed((()=>{const{colDesc:e,xGroupByDesc:r,data:o,modelName:s}=a.chartData,i=e.length,l={title:{text:s},series:e.map(((e,c)=>{const s={name:e,type:"pie",center:["50%","50%"],data:[],emphasis:{itemStyle:{shadowBlur:10,shadowOffsetX:0,shadowColor:"rgba(0, 0, 0, 0.5)"}},label:{formatter:"{b}:{c}({d}%)",rich:{b:{color:"#4C5058",fontSize:14,fontWeight:"bold",lineHeight:33}}}};let l=5;const n=t.orderBy(t.cloneDeep(o),[e],["desc"]),u=n.reduce(((t,r)=>t+Number(r[e])),0);if(o.length>l)for(;l<9;){const t=n.slice(0,l);if(t.reduce(((t,r)=>t+Number(r[e])),0)/u>.9||8===l){const a=n.slice(l,n.length-1);s.data=o.map((o=>{let a={};return t.forEach((t=>{JSON.stringify(t)===JSON.stringify(o)&&(a={name:r?.colDesc?o[r.colDesc]:"",value:o[e]})})),a})).filter((e=>e)),s.data.push({name:"其它",value:a.reduce(((t,r)=>t+Number(r[e])),0)});break}l++}else s.data=o.map((t=>({name:r?.colDesc&&t[r.colDesc]||"",value:Number(t[e]||0)})));if(1===i?s.center=["50%","60%"]:2===i?0===c?(s.right="40%",s.left="",s.center=["40%","60%"]):(s.right="",s.left="40%",s.center=["60%","60%"]):3===i?0===c?(s.right="40%",s.bottom="50%",s.top="",s.left="",s.center=["40%","78%"]):1===c?(s.right="",s.bottom="50%",s.top="",s.left="40%",s.center=["60%","78%"]):(s.right="40%",s.bottom="",s.top="50%",s.left="",s.center=["40%","60%"]):4===i&&(0===c?(s.right="40%",s.bottom="50%",s.top="",s.left="",s.center=["40%","78%"]):1===c?(s.right="",s.bottom="50%",s.top="",s.left="40%",s.center=["60%","78%"]):2===c?(s.right="40%",s.bottom="",s.top="50%",s.left="",s.center=["40%","60%"]):(s.right="",s.bottom="",s.top="50%",s.left="40%",s.center=["60%","60%"])),"pie-borderRadius"===a.subShowType)s.radius=["50%","70%"];else s.radius="50%";return s}))};return c(l,a.chartOptions)}));return o.useCharts({chartDOM:s,chartOptions:i,chartData:e.computed((()=>a.chartData))}),(t,r)=>(e.openBlock(),e.createElementBlock("div",{ref_key:"dataChartPie",ref:s,class:"data-chart-pie"},null,512))}});exports.default=a;
|
2
2
|
//# sourceMappingURL=pie.vue.cjs.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"pie.vue.cjs","sources":["../../../../../../../packages/components/src/data-chart/src/components/pie.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { PieSeriesOption } from
|
1
|
+
{"version":3,"file":"pie.vue.cjs","sources":["../../../../../../../packages/components/src/data-chart/src/components/pie.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { PieSeriesOption } from \"echarts/charts\";\nimport type { EChartsOption, IFormatPublicData } from \"../types\";\nimport { cloneDeep, orderBy } from \"lodash-es\";\nimport { InjectionChartMerge } from \"../utils/injectionKeys\";\nimport { useCharts } from \"../utils/useCharts\";\n\ndefineOptions({\n name: \"DataChartPie\",\n});\nconst {\n chartData = {\n colDesc: [],\n xGroupByDesc: {\n colDesc: \"\",\n groupByDesc: \"\",\n groupByValues: [],\n xAxis: false,\n },\n groupByDesc: [],\n data: [],\n modelName: \"\",\n },\n subShowType = \"pie-simple\",\n chartOptions,\n} = defineProps<{\n chartData: IFormatPublicData;\n subShowType: string;\n chartOptions: EChartsOption;\n}>();\nconst merge = inject(InjectionChartMerge, (v: any) => v, true);\n\nconst dataChartPie = ref(null);\nconst pieChartOptions = computed<EChartsOption>(() => {\n const { colDesc, xGroupByDesc, data, modelName } = chartData;\n const colDescLength = colDesc.length;\n const config = {\n title: { text: modelName },\n series: colDesc.map((item, index) => {\n const seriesItem: PieSeriesOption = {\n name: item,\n type: \"pie\",\n center: [\"50%\", \"50%\"],\n data: [],\n emphasis: {\n itemStyle: {\n shadowBlur: 10,\n shadowOffsetX: 0,\n shadowColor: \"rgba(0, 0, 0, 0.5)\",\n },\n },\n label: {\n formatter: \"{b}:{c}({d}%)\",\n rich: {\n b: {\n color: \"#4C5058\",\n fontSize: 14,\n fontWeight: \"bold\",\n lineHeight: 33,\n },\n },\n },\n };\n\n let cutNum = 5;\n const orderByData = orderBy(cloneDeep(data), [item], [\"desc\"]);\n // 总数\n const totalDesc = orderByData.reduce(\n (prev, cur) => prev + Number(cur[item]),\n 0\n );\n if (data.length > cutNum) {\n while (cutNum < 9) {\n const headerData = orderByData.slice(0, cutNum);\n // 前 cutNum 个总数\n const headerTotal = headerData.reduce(\n (prev, cur) => prev + Number(cur[item]),\n 0\n );\n // 前五总占比\n const headerScale = headerTotal / totalDesc;\n if (headerScale > 0.9 || cutNum === 8) {\n //\n const footerData = orderByData.slice(\n cutNum,\n orderByData.length - 1\n );\n seriesItem.data = data\n .map((yItem) => {\n let obj = {};\n headerData.forEach((headerDataItem) => {\n if (\n JSON.stringify(headerDataItem) === JSON.stringify(yItem)\n ) {\n obj = {\n name: xGroupByDesc?.colDesc\n ? yItem[xGroupByDesc.colDesc]\n : \"\",\n value: yItem[item],\n };\n }\n });\n return obj;\n })\n .filter((v) => v);\n seriesItem.data.push({\n name: \"其它\",\n value: footerData.reduce(\n (prev, cur) => prev + Number(cur[item]),\n 0\n ),\n });\n\n break;\n } else {\n cutNum++;\n }\n }\n } else {\n seriesItem.data = data.map((yItem) => ({\n name: xGroupByDesc?.colDesc ? (yItem[xGroupByDesc.colDesc] || '') : \"\",\n value: Number(yItem[item] || 0),\n }));\n }\n\n if (colDescLength === 1) {\n seriesItem.center = [\"50%\", \"60%\"];\n } else if (colDescLength === 2) {\n if (index === 0) {\n seriesItem.right = \"40%\";\n seriesItem.left = \"\";\n seriesItem.center = [\"40%\", \"60%\"];\n } else {\n seriesItem.right = \"\";\n seriesItem.left = \"40%\";\n seriesItem.center = [\"60%\", \"60%\"];\n }\n } else if (colDescLength === 3) {\n if (index === 0) {\n seriesItem.right = \"40%\";\n seriesItem.bottom = \"50%\";\n seriesItem.top = \"\";\n seriesItem.left = \"\";\n seriesItem.center = [\"40%\", \"78%\"];\n } else if (index === 1) {\n seriesItem.right = \"\";\n seriesItem.bottom = \"50%\";\n seriesItem.top = \"\";\n seriesItem.left = \"40%\";\n seriesItem.center = [\"60%\", \"78%\"];\n } else {\n seriesItem.right = \"40%\";\n seriesItem.bottom = \"\";\n seriesItem.top = \"50%\";\n seriesItem.left = \"\";\n seriesItem.center = [\"40%\", \"60%\"];\n }\n } else if (colDescLength === 4) {\n if (index === 0) {\n seriesItem.right = \"40%\";\n seriesItem.bottom = \"50%\";\n seriesItem.top = \"\";\n seriesItem.left = \"\";\n seriesItem.center = [\"40%\", \"78%\"];\n } else if (index === 1) {\n seriesItem.right = \"\";\n seriesItem.bottom = \"50%\";\n seriesItem.top = \"\";\n seriesItem.left = \"40%\";\n seriesItem.center = [\"60%\", \"78%\"];\n } else if (index === 2) {\n seriesItem.right = \"40%\";\n seriesItem.bottom = \"\";\n seriesItem.top = \"50%\";\n seriesItem.left = \"\";\n seriesItem.center = [\"40%\", \"60%\"];\n } else {\n seriesItem.right = \"\";\n seriesItem.bottom = \"\";\n seriesItem.top = \"50%\";\n seriesItem.left = \"40%\";\n seriesItem.center = [\"60%\", \"60%\"];\n }\n }\n // 处理图表形状\n switch (subShowType) {\n case \"pie-borderRadius\":\n seriesItem.radius = [\"50%\", \"70%\"];\n break;\n case \"pie-simple\":\n seriesItem.radius = \"50%\";\n break;\n default:\n seriesItem.radius = \"50%\";\n break;\n }\n return seriesItem;\n }),\n };\n return merge(config, chartOptions);\n});\n\nuseCharts({\n chartDOM: dataChartPie,\n chartOptions: pieChartOptions,\n chartData: computed(() => chartData),\n});\n</script>\n\n<template>\n <div ref=\"dataChartPie\" class=\"data-chart-pie\" />\n</template>\n"],"names":["merge","inject","InjectionChartMerge","v","dataChartPie","ref","pieChartOptions","computed","colDesc","xGroupByDesc","data","modelName","__props","chartData","colDescLength","length","config","title","text","series","map","item","index","seriesItem","name","type","center","emphasis","itemStyle","shadowBlur","shadowOffsetX","shadowColor","label","formatter","rich","b","color","fontSize","fontWeight","lineHeight","cutNum","orderByData","orderBy","cloneDeep","totalDesc","reduce","prev","cur","Number","headerData","slice","footerData","yItem","obj","forEach","headerDataItem","JSON","stringify","value","filter","push","right","left","bottom","top","subShowType","radius","chartOptions","useCharts","chartDOM"],"mappings":"ygBA8BA,MAAMA,EAAQC,EAAAA,OAAOC,EAAAA,qBAAsBC,GAAWA,IAAG,GAEnDC,EAAeC,MAAI,MACnBC,EAAkBC,EAAAA,UAAwB,KAC9C,MAAMC,QAAEA,EAASC,aAAAA,EAAAC,KAAcA,EAAMC,UAAAA,GAAcC,EAASC,UACtDC,EAAgBN,EAAQO,OACxBC,EAAS,CACbC,MAAO,CAAEC,KAAMP,GACfQ,OAAQX,EAAQY,KAAI,CAACC,EAAMC,KACzB,MAAMC,EAA8B,CAClCC,KAAMH,EACNI,KAAM,MACNC,OAAQ,CAAC,MAAO,OAChBhB,KAAM,GACNiB,SAAU,CACRC,UAAW,CACTC,WAAY,GACZC,cAAe,EACfC,YAAa,uBAGjBC,MAAO,CACLC,UAAW,gBACXC,KAAM,CACJC,EAAG,CACDC,MAAO,UACPC,SAAU,GACVC,WAAY,OACZC,WAAY,OAMpB,IAAIC,EAAS,EACP,MAAAC,EAAcC,EAAQA,QAAAC,YAAUjC,GAAO,CAACW,GAAO,CAAC,SAEhDuB,EAAYH,EAAYI,QAC5B,CAACC,EAAMC,IAAQD,EAAOE,OAAOD,EAAI1B,KACjC,GAEE,GAAAX,EAAKK,OAASyB,EAChB,KAAOA,EAAS,GAAG,CACjB,MAAMS,EAAaR,EAAYS,MAAM,EAAGV,GAQpC,GANgBS,EAAWJ,QAC7B,CAACC,EAAMC,IAAQD,EAAOE,OAAOD,EAAI1B,KACjC,GAGgCuB,EAChB,IAAkB,IAAXJ,EAAc,CAErC,MAAMW,EAAaV,EAAYS,MAC7BV,EACAC,EAAY1B,OAAS,GAEvBQ,EAAWb,KAAOA,EACfU,KAAKgC,IACJ,IAAIC,EAAM,CAAC,EAaJ,OAZIJ,EAAAK,SAASC,IAEhBC,KAAKC,UAAUF,KAAoBC,KAAKC,UAAUL,KAE5CC,EAAA,CACJ7B,KAAMf,GAAcD,QAChB4C,EAAM3C,EAAaD,SACnB,GACJkD,MAAON,EAAM/B,IACf,IAGGgC,CAAA,IAERM,QAAQxD,GAAMA,IACjBoB,EAAWb,KAAKkD,KAAK,CACnBpC,KAAM,KACNkC,MAAOP,EAAWN,QAChB,CAACC,EAAMC,IAAQD,EAAOE,OAAOD,EAAI1B,KACjC,KAIJ,KAAA,CAEAmB,GACF,MAGFjB,EAAWb,KAAOA,EAAKU,KAAKgC,IAAW,CACrC5B,KAAMf,GAAcD,SAAW4C,EAAM3C,EAAaD,UAAkB,GACpEkD,MAAOV,OAAOI,EAAM/B,IAAS,OAgEjC,GA5DsB,IAAlBP,EACSS,EAAAG,OAAS,CAAC,MAAO,OACD,IAAlBZ,EACK,IAAVQ,GACFC,EAAWsC,MAAQ,MACnBtC,EAAWuC,KAAO,GACPvC,EAAAG,OAAS,CAAC,MAAO,SAE5BH,EAAWsC,MAAQ,GACnBtC,EAAWuC,KAAO,MACPvC,EAAAG,OAAS,CAAC,MAAO,QAEH,IAAlBZ,EACK,IAAVQ,GACFC,EAAWsC,MAAQ,MACnBtC,EAAWwC,OAAS,MACpBxC,EAAWyC,IAAM,GACjBzC,EAAWuC,KAAO,GACPvC,EAAAG,OAAS,CAAC,MAAO,QACT,IAAVJ,GACTC,EAAWsC,MAAQ,GACnBtC,EAAWwC,OAAS,MACpBxC,EAAWyC,IAAM,GACjBzC,EAAWuC,KAAO,MACPvC,EAAAG,OAAS,CAAC,MAAO,SAE5BH,EAAWsC,MAAQ,MACnBtC,EAAWwC,OAAS,GACpBxC,EAAWyC,IAAM,MACjBzC,EAAWuC,KAAO,GACPvC,EAAAG,OAAS,CAAC,MAAO,QAEH,IAAlBZ,IACK,IAAVQ,GACFC,EAAWsC,MAAQ,MACnBtC,EAAWwC,OAAS,MACpBxC,EAAWyC,IAAM,GACjBzC,EAAWuC,KAAO,GACPvC,EAAAG,OAAS,CAAC,MAAO,QACT,IAAVJ,GACTC,EAAWsC,MAAQ,GACnBtC,EAAWwC,OAAS,MACpBxC,EAAWyC,IAAM,GACjBzC,EAAWuC,KAAO,MACPvC,EAAAG,OAAS,CAAC,MAAO,QACT,IAAVJ,GACTC,EAAWsC,MAAQ,MACnBtC,EAAWwC,OAAS,GACpBxC,EAAWyC,IAAM,MACjBzC,EAAWuC,KAAO,GACPvC,EAAAG,OAAS,CAAC,MAAO,SAE5BH,EAAWsC,MAAQ,GACnBtC,EAAWwC,OAAS,GACpBxC,EAAWyC,IAAM,MACjBzC,EAAWuC,KAAO,MACPvC,EAAAG,OAAS,CAAC,MAAO,SAKzB,qBADCd,EAAAqD,YAEO1C,EAAA2C,OAAS,CAAC,MAAO,YAM5B3C,EAAW2C,OAAS,MAGjB,OAAA3C,CAAA,KAGJ,OAAAvB,EAAMgB,EAAQJ,EAAAuD,aAAY,WAGzBC,YAAA,CACRC,SAAUjE,EACV+D,aAAc7D,EACdO,UAAWN,EAAAA,UAAS,IAAMK,EAAAC"}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"file-upload.vue.cjs","sources":["../../../../../../packages/components/src/file-upload/src/file-upload.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { UploadProps, UploadUserFile } from \"element-plus\";\nimport { UploadFilled } from \"@element-plus/icons-vue\";\nimport { useNamespace } from \"@qxs-bns/hooks\";\n\ndefineOptions({\n name: \"QxsFileUpload\",\n});\n\nconst {\n name = \"file\",\n size = 20,\n max = 3,\n files = [],\n notip = false,\n accept = \"zip,rar\",\n} = defineProps<{\n action: UploadProps[\"action\"];\n headers?: UploadProps[\"headers\"];\n data?: UploadProps[\"data\"];\n name?: UploadProps[\"name\"];\n size?: number;\n max?: number;\n accept?: string;\n files?: UploadUserFile[];\n notip?: boolean;\n ext?: string[];\n}>();\n\nconst emit = defineEmits([\"onSuccess\"]);\n\nconst ns = useNamespace(\"file-upload\");\n\nconst exts = computed(() => {\n return accept.split(\",\")
|
1
|
+
{"version":3,"file":"file-upload.vue.cjs","sources":["../../../../../../packages/components/src/file-upload/src/file-upload.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { UploadProps, UploadUserFile } from \"element-plus\";\nimport { UploadFilled } from \"@element-plus/icons-vue\";\nimport { useNamespace } from \"@qxs-bns/hooks\";\n\ndefineOptions({\n name: \"QxsFileUpload\",\n});\n\nconst {\n name = \"file\",\n size = 20,\n max = 3,\n files = [],\n notip = false,\n accept = \"zip,rar\",\n} = defineProps<{\n action: UploadProps[\"action\"];\n headers?: UploadProps[\"headers\"];\n data?: UploadProps[\"data\"];\n name?: UploadProps[\"name\"];\n size?: number;\n max?: number;\n accept?: string;\n files?: UploadUserFile[];\n notip?: boolean;\n ext?: string[];\n}>();\n\nconst emit = defineEmits([\"onSuccess\"]);\n\nconst ns = useNamespace(\"file-upload\");\n\nconst exts = computed(() => {\n return accept.split(\",\");\n});\nconst beforeUpload: UploadProps[\"beforeUpload\"] = (file) => {\n const fileName = file.name.split(\".\");\n const fileExt = fileName.at(-1) ?? \"\";\n const isTypeOk = exts.value.includes(fileExt);\n const isSizeOk = file.size / 1024 / 1024 < size;\n if (!isTypeOk) {\n ElMessage.error(`上传文件只支持 ${exts.value.join(\" / \")} 格式!`);\n }\n if (!isSizeOk) {\n ElMessage.error(`上传文件大小不能超过 ${size}MB!`);\n }\n return isTypeOk && isSizeOk;\n};\n\nconst onExceed: UploadProps[\"onExceed\"] = () => {\n ElMessage.warning(\"文件上传超过限制\");\n};\n\nconst onSuccess: UploadProps[\"onSuccess\"] = (res, file, fileList) => {\n emit(\"onSuccess\", res, file, fileList);\n};\n</script>\n\n<template>\n <el-upload\n :headers=\"headers\"\n :action=\"action\"\n :data=\"data\"\n :name=\"name\"\n :before-upload=\"beforeUpload\"\n :on-exceed=\"onExceed\"\n :on-success=\"onSuccess\"\n :file-list=\"files\"\n :limit=\"max\"\n drag\n :class=\"ns.e('control')\"\n >\n <div class=\"slot\">\n <el-icon class=\"el-icon--upload\">\n <UploadFilled />\n </el-icon>\n <div class=\"el-upload__text\">将文件拖到此处,或<em>点击上传</em></div>\n </div>\n <template #tip>\n <div v-if=\"!notip\" class=\"el-upload__tip\">\n <div style=\"display: inline-block\">\n <el-alert\n :title=\"`上传文件支持 ${exts.join(\n ' / '\n )} 格式,单个文件大小不超过 ${size}MB,且文件数量不超过 ${max} 个`\"\n type=\"info\"\n show-icon\n :closable=\"false\"\n />\n </div>\n </div>\n </template>\n </el-upload>\n</template>\n"],"names":["emit","__emit","ns","useNamespace","exts","computed","__props","accept","split","beforeUpload","file","fileExt","name","at","isTypeOk","value","includes","isSizeOk","size","ElMessage","error","join","onExceed","warning","onSuccess","res","fileList"],"mappings":"2wBA6BA,MAAMA,EAAOC,EAEPC,EAAKC,eAAa,eAElBC,EAAOC,EAAAA,UAAS,IACbC,EAAAC,OAAOC,MAAM,OAEhBC,EAA6CC,IACjD,MACMC,EADWD,EAAKE,KAAKJ,MAAM,KACRK,IAAG,IAAO,GAC7BC,EAAWV,EAAKW,MAAMC,SAASL,GAC/BM,EAAWP,EAAKQ,KAAO,KAAO,KAAOZ,EAAIY,KAO/C,OANKJ,GACHK,YAAUC,MAAM,WAAWhB,EAAKW,MAAMM,KAAK,cAExCJ,GACHE,EAAAA,UAAUC,MAAM,cAAcd,EAAIY,WAE7BJ,GAAYG,CAAA,EAGfK,EAAoC,KACxCH,EAAAA,UAAUI,QAAQ,WAAU,EAGxBC,EAAsC,CAACC,EAAKf,EAAMgB,KACjD1B,EAAA,YAAayB,EAAKf,EAAMgB,EAAQ"}
|
@@ -1,2 +1,2 @@
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("vue"),t=require("@qxs-bns/hooks"),l=require("
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("vue"),t=require("@qxs-bns/hooks"),l=require("./composables.cjs"),a=require("@vueuse/core");const o=["src"];var u=e.defineComponent({name:"QxsPhotoCropTool",__name:"photo-crop-tool",props:{imgFile:{type:Object,default:()=>null},aspectRatio:{type:String,default:()=>"16 / 9"},defaultWidth:{type:Number,default:()=>320},defaultHeight:{type:Number,default:()=>180},zoomType:{type:String,default:()=>"fixed"}},setup(u,{expose:i}){const n=u;let r=0,s=0,v=0,h=0;const c=t.useNamespace("photo-crop-tool"),f=e.ref(null),p=e.ref(null),d=e.ref(null),m=e.ref(""),g=e.ref(""),y=e.ref({x:0,y:0}),w=e.ref({width:n.defaultWidth,height:n.defaultHeight,x:0,y:0}),{width:x,height:b}=a.useElementSize(f),{width:z}=a.useElementSize(d),{x:E,y:N,style:R}=a.useDraggable(f,{containerElement:p,draggingElement:f,disabled:e.computed((()=>!!g.value)),exact:!0,initialValue:y}),k=e.computed((()=>n.imgFile?URL.createObjectURL(n.imgFile):""));e.watch((()=>n.imgFile),(e=>{e&&!e.type.startsWith("image/")?m.value="文件类型错误":m.value=""}));const H=e.computed((()=>(d.value?.naturalWidth||0)/z.value)),C=e.computed((()=>{const e={left:0,top:0};return"bottom-right"===g.value?(e.left=w.value.x,e.top=w.value.y):"top-left"===g.value?(e.left=w.value.x-x.value,e.top=w.value.y-b.value):"top-right"===g.value?(e.top=w.value.y-b.value,e.left=w.value.x):"bottom-left"===g.value&&(e.left=w.value.x-x.value,e.top=w.value.y),e})),T=e.computed((()=>{const{aspectRatio:e}=n,t={width:`${w.value.width||n.defaultWidth}`,height:`${w.value.height||n.defaultHeight}`,"aspect-ratio":e,top:`${C.value.top}px`,left:`${C.value.left}px`};return"free"===n.zoomType?delete t["aspect-ratio"]:"fixed"===n.zoomType&&delete t.height,c.cssVarBlock(t)}));function F(e){return e*H.value}function M(e,t){const l=p.value?.clientWidth||1/0,a=p.value?.clientHeight||1/0;return{width:Math.min(Math.max(e,0),l),height:Math.min(Math.max(t,0),a)}}function W(e){const t=e.clientX-r,l=e.clientY-s;if("bottom-right"===g.value){if("free"===n.zoomType){const{width:e,height:a}=M(v+t,h+l);w.value.width=e,w.value.height=a}else if("fixed"===n.zoomType){const e=Number.parseFloat(n.aspectRatio.split(" / ")[0])/Number.parseFloat(n.aspectRatio.split(" / ")[1]);let l=v+t,a=l/e;const{width:o,height:u}=M(l,a);u>(p.value?.clientHeight||1/0)&&(a=p.value?.clientHeight||1/0,l=a*e),w.value.width=o,w.value.height=u}}else if("top-left"===g.value){if("free"===n.zoomType){const{width:e,height:a}=M(v-t,h-l);w.value.width=e,w.value.height=a}else if("fixed"===n.zoomType){const e=Number.parseFloat(n.aspectRatio.split(" / ")[0])/Number.parseFloat(n.aspectRatio.split(" / ")[1]);let l=v-t,a=l/e;const{width:o,height:u}=M(l,a);u>(p.value?.clientHeight||1/0)&&(a=p.value?.clientHeight||1/0,l=a*e),w.value.width=o,w.value.height=u}E.value=C.value.left,N.value=C.value.top}else if("top-right"===g.value){if("free"===n.zoomType){const{width:e,height:a}=M(v+t,h-l);w.value.width=e,w.value.height=a}else if("fixed"===n.zoomType){const e=Number.parseFloat(n.aspectRatio.split(" / ")[0])/Number.parseFloat(n.aspectRatio.split(" / ")[1]);let l=v+t,a=l/e;const{width:o,height:u}=M(l,a);u>(p.value?.clientHeight||1/0)&&(a=p.value?.clientHeight||1/0,l=a*e),w.value.width=o,w.value.height=u}E.value=C.value.left,N.value=C.value.top}else if("bottom-left"===g.value){if("free"===n.zoomType){const{width:e,height:a}=M(v-t,h+l);w.value.width=e,w.value.height=a}else if("fixed"===n.zoomType){const e=Number.parseFloat(n.aspectRatio.split(" / ")[0])/Number.parseFloat(n.aspectRatio.split(" / ")[1]);let l=v-t,a=l/e;const{width:o,height:u}=M(l,a);u>(p.value?.clientHeight||1/0)&&(a=p.value?.clientHeight||1/0,l=a*e),w.value.width=o,w.value.height=u}E.value=C.value.left,N.value=C.value.top}e.preventDefault(),e.stopPropagation()}function B(e,t){g.value=t,r=e.clientX,s=e.clientY,v=w.value.width,h=w.value.height,"bottom-right"===t?(w.value.x=E.value,w.value.y=N.value):"top-left"===t?(w.value.x=E.value+x.value,w.value.y=N.value+b.value):"top-right"===t?(w.value.x=E.value,w.value.y=N.value+b.value):"bottom-left"===t&&(w.value.x=E.value+x.value,w.value.y=N.value)}function L(){g.value=""}return document.addEventListener("mouseup",L),document.addEventListener("mousemove",W),e.onMounted((()=>{e.nextTick((()=>{y.value.x=(p.value?.offsetWidth||0)/2-w.value.width/2,y.value.y=(p.value?.offsetHeight||0)/2-w.value.height/2}))})),e.onUnmounted((()=>{k.value&&URL.revokeObjectURL(k.value),document.removeEventListener("mouseup",L),document.removeEventListener("mousemove",W)})),i({crop:async function(e=d.value){let t="transparent";p.value&&(t=window.getComputedStyle(p.value).backgroundColor);const a=document.createElement("canvas");a.width=F(p.value?.clientWidth||0),a.height=F(p.value?.clientHeight||0);const{drawImage:o,cropCanvas:u,drawColor:i}=l.useCanvas(a);return i(0,0,a.width,a.height,t),o(e,F(e.offsetLeft),F(e.offsetTop),e.naturalWidth,e.naturalHeight),await u(F(E.value),F(N.value),F(x.value),F(b.value))},resize:function(){w.value.width=n.defaultWidth,w.value.height=n.defaultHeight,E.value=0,N.value=0}}),(t,l)=>(e.openBlock(),e.createElementBlock("div",{ref_key:"containerBoxRef",ref:p,class:e.normalizeClass([e.unref(c).e("img-box")])},[e.unref(m)?(e.openBlock(),e.createElementBlock("div",{key:0,class:e.normalizeClass([e.unref(c).e("error-message")])},e.toDisplayString(e.unref(m)),3)):(e.openBlock(),e.createElementBlock(e.Fragment,{key:1},[e.createElementVNode("img",{ref_key:"imgRef",ref:d,class:e.normalizeClass([e.unref(c).e("image")]),src:e.unref(k)},null,10,o),e.createElementVNode("div",{ref_key:"cropBoxRef",ref:f,class:e.normalizeClass([e.unref(c).e("crop-tool-box")]),style:e.normalizeStyle([e.unref(T),e.unref(g)?`left: ${e.unref(C).left}px;top: ${e.unref(C).top}px`:e.unref(R)])},[e.createElementVNode("div",{class:e.normalizeClass([e.unref(c).e("top-left")]),onMousedown:l[0]||(l[0]=e=>B(e,"top-left"))},null,34),e.createElementVNode("div",{class:e.normalizeClass([e.unref(c).e("top-right")]),onMousedown:l[1]||(l[1]=e=>B(e,"top-right"))},null,34),e.createElementVNode("div",{class:e.normalizeClass([e.unref(c).e("bottom-right")]),onMousedown:l[2]||(l[2]=e=>B(e,"bottom-right"))},null,34),e.createElementVNode("div",{class:e.normalizeClass([e.unref(c).e("bottom-left")]),onMousedown:l[3]||(l[3]=e=>B(e,"bottom-left"))},null,34)],6)],64))],2))}});exports.default=u;
|
2
2
|
//# sourceMappingURL=photo-crop-tool.vue.cjs.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"photo-crop-tool.vue.cjs","sources":["../../../../../../packages/components/src/photo-crop-tool/src/photo-crop-tool.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { PropType } from 'vue'\nimport { useNamespace } from '@qxs-bns/hooks'\nimport { useDraggable, useElementSize } from '@vueuse/core'\nimport { useCanvas } from './composables'\n\ndefineOptions({\n name: 'QxsPhotoCropTool',\n})\n\nconst props = defineProps({\n imgFile: {\n type: Object as PropType<File>,\n default: () => null,\n },\n aspectRatio: {\n type: String,\n default: () => '16 / 9',\n },\n defaultWidth: {\n type: Number,\n default: () => 320,\n },\n defaultHeight: {\n type: Number,\n default: () => 180,\n },\n /**\n * free 自由缩放\n * fixed 固定比例缩放\n */\n zoomType: {\n type: String,\n default: () => 'fixed',\n },\n})\nlet startX = 0\nlet startY = 0\nlet startWidth = 0\nlet startHeight = 0\n\nconst ns = useNamespace('photo-crop-tool')\n\nconst cropBoxRef = ref<HTMLElement | null>(null)\nconst containerBoxRef = ref<HTMLElement | null>(null)\nconst imgRef = ref<HTMLImageElement | null>(null)\nconst errorMessage = ref('')\nconst dargPoint = ref('')\nconst initialValue = ref({\n x: 0,\n y: 0,\n})\nconst cropInfo = ref({\n width: props.defaultWidth,\n height: props.defaultHeight,\n x: 0,\n y: 0,\n})\n\nconst { width, height } = useElementSize(cropBoxRef)\nconst { width: imgWidth } = useElementSize(imgRef)\n\nconst { x, y, style } = useDraggable(cropBoxRef, {\n containerElement: containerBoxRef,\n draggingElement: cropBoxRef,\n disabled: computed(() => !!dargPoint.value),\n exact: true,\n initialValue,\n})\n\nconst imageUrl = computed(() => {\n if (!props.imgFile) {\n return ''\n }\n return URL.createObjectURL(props.imgFile)\n})\n\nwatch(\n () => props.imgFile,\n (newFile: File | null) => {\n if (newFile && !newFile.type.startsWith('image/')) {\n errorMessage.value = '文件类型错误'\n }\n else {\n errorMessage.value = ''\n }\n },\n)\n\nconst ratio = computed(() => {\n return (imgRef.value?.naturalWidth || 0) / imgWidth.value\n})\n\nconst customStyle = computed(() => {\n const position = {\n left: 0,\n top: 0,\n }\n if (dargPoint.value === 'bottom-right') {\n position.left = cropInfo.value.x\n position.top = cropInfo.value.y\n }\n else if (dargPoint.value === 'top-left') {\n position.left = cropInfo.value.x - width.value\n position.top = cropInfo.value.y - height.value\n }\n else if (dargPoint.value === 'top-right') {\n position.top = cropInfo.value.y - height.value\n position.left = cropInfo.value.x\n }\n else if (dargPoint.value === 'bottom-left') {\n position.left = cropInfo.value.x - width.value\n position.top = cropInfo.value.y\n }\n return position\n})\n\nconst sizeStyle = computed(() => {\n const { aspectRatio } = props\n\n const style: {\n 'height'?: string\n 'width': string\n 'aspect-ratio'?: string\n 'top': string\n 'left': string\n } = {\n 'width': `${cropInfo.value.width || props.defaultWidth}`,\n 'height': `${cropInfo.value.height || props.defaultHeight}`,\n 'aspect-ratio': aspectRatio,\n 'top': `${customStyle.value.top}px`,\n 'left': `${customStyle.value.left}px`,\n }\n if (props.zoomType === 'free') {\n delete style['aspect-ratio']\n }\n else if (props.zoomType === 'fixed') {\n delete style.height\n }\n return ns.cssVarBlock(style)\n})\n\nfunction zoom(pixel: number) {\n return pixel * ratio.value\n}\nasync function crop(img: HTMLImageElement = imgRef.value!) {\n let backgroundColor = 'transparent'\n if (containerBoxRef.value) {\n backgroundColor = window.getComputedStyle(\n containerBoxRef.value,\n ).backgroundColor\n }\n const canvas = document.createElement('canvas')\n canvas.width = zoom(containerBoxRef.value?.clientWidth || 0)\n canvas.height = zoom(containerBoxRef.value?.clientHeight || 0)\n const { drawImage, cropCanvas, drawColor } = useCanvas(canvas)\n drawColor(0, 0, canvas.width, canvas.height, backgroundColor)\n drawImage(\n img,\n zoom(img.offsetLeft),\n zoom(img.offsetTop),\n img.naturalWidth,\n img.naturalHeight,\n )\n return await cropCanvas(\n zoom(x.value),\n zoom(y.value),\n zoom(width.value),\n zoom(height.value),\n )\n}\n\nfunction checkBoundaries(\n newWidth: number,\n newHeight: number,\n): { width: number, height: number } {\n const maxWidth = containerBoxRef.value?.clientWidth || Infinity\n const maxHeight = containerBoxRef.value?.clientHeight || Infinity\n\n return {\n width: Math.min(Math.max(newWidth, 0), maxWidth),\n height: Math.min(Math.max(newHeight, 0), maxHeight),\n }\n}\n\nfunction mousemove(e: MouseEvent) {\n const deltaX = e.clientX - startX\n const deltaY = e.clientY - startY\n\n if (dargPoint.value === 'bottom-right') {\n if (props.zoomType === 'free') {\n const { width, height } = checkBoundaries(\n startWidth + deltaX,\n startHeight + deltaY,\n )\n cropInfo.value.width = width\n cropInfo.value.height = height\n }\n else if (props.zoomType === 'fixed') {\n const aspectRatio\n = Number.parseFloat(props.aspectRatio.split(' / ')[0])\n / Number.parseFloat(props.aspectRatio.split(' / ')[1])\n let newWidth = startWidth + deltaX\n let newHeight = newWidth / aspectRatio\n const { width, height } = checkBoundaries(newWidth, newHeight)\n if (height > (containerBoxRef.value?.clientHeight || Infinity)) {\n newHeight = containerBoxRef.value?.clientHeight || Infinity\n newWidth = newHeight * aspectRatio\n }\n cropInfo.value.width = width\n cropInfo.value.height = height\n }\n }\n else if (dargPoint.value === 'top-left') {\n if (props.zoomType === 'free') {\n const { width, height } = checkBoundaries(\n startWidth - deltaX,\n startHeight - deltaY,\n )\n cropInfo.value.width = width\n cropInfo.value.height = height\n }\n else if (props.zoomType === 'fixed') {\n const aspectRatio\n = Number.parseFloat(props.aspectRatio.split(' / ')[0])\n / Number.parseFloat(props.aspectRatio.split(' / ')[1])\n let newWidth = startWidth - deltaX\n let newHeight = newWidth / aspectRatio\n const { width, height } = checkBoundaries(newWidth, newHeight)\n if (height > (containerBoxRef.value?.clientHeight || Infinity)) {\n newHeight = containerBoxRef.value?.clientHeight || Infinity\n newWidth = newHeight * aspectRatio\n }\n cropInfo.value.width = width\n cropInfo.value.height = height\n }\n x.value = customStyle.value.left\n y.value = customStyle.value.top\n }\n else if (dargPoint.value === 'top-right') {\n if (props.zoomType === 'free') {\n const { width, height } = checkBoundaries(\n startWidth + deltaX,\n startHeight - deltaY,\n )\n cropInfo.value.width = width\n cropInfo.value.height = height\n }\n else if (props.zoomType === 'fixed') {\n const aspectRatio\n = Number.parseFloat(props.aspectRatio.split(' / ')[0])\n / Number.parseFloat(props.aspectRatio.split(' / ')[1])\n let newWidth = startWidth + deltaX\n let newHeight = newWidth / aspectRatio\n const { width, height } = checkBoundaries(newWidth, newHeight)\n if (height > (containerBoxRef.value?.clientHeight || Infinity)) {\n newHeight = containerBoxRef.value?.clientHeight || Infinity\n newWidth = newHeight * aspectRatio\n }\n cropInfo.value.width = width\n cropInfo.value.height = height\n }\n x.value = customStyle.value.left\n y.value = customStyle.value.top\n }\n else if (dargPoint.value === 'bottom-left') {\n if (props.zoomType === 'free') {\n const { width, height } = checkBoundaries(\n startWidth - deltaX,\n startHeight + deltaY,\n )\n cropInfo.value.width = width\n cropInfo.value.height = height\n }\n else if (props.zoomType === 'fixed') {\n const aspectRatio\n = Number.parseFloat(props.aspectRatio.split(' / ')[0])\n / Number.parseFloat(props.aspectRatio.split(' / ')[1])\n let newWidth = startWidth - deltaX\n let newHeight = newWidth / aspectRatio\n const { width, height } = checkBoundaries(newWidth, newHeight)\n if (height > (containerBoxRef.value?.clientHeight || Infinity)) {\n newHeight = containerBoxRef.value?.clientHeight || Infinity\n newWidth = newHeight * aspectRatio\n }\n cropInfo.value.width = width\n cropInfo.value.height = height\n }\n x.value = customStyle.value.left\n y.value = customStyle.value.top\n }\n e.preventDefault()\n e.stopPropagation()\n}\n\nfunction mousedown(e: MouseEvent, point: string) {\n dargPoint.value = point\n startX = e.clientX\n startY = e.clientY\n startWidth = cropInfo.value.width\n startHeight = cropInfo.value.height\n\n if (point === 'bottom-right') {\n cropInfo.value.x = x.value\n cropInfo.value.y = y.value\n }\n else if (point === 'top-left') {\n cropInfo.value.x = x.value + width.value\n cropInfo.value.y = y.value + height.value\n }\n else if (point === 'top-right') {\n cropInfo.value.x = x.value\n cropInfo.value.y = y.value + height.value\n }\n else if (point === 'bottom-left') {\n cropInfo.value.x = x.value + width.value\n cropInfo.value.y = y.value\n }\n}\n\nfunction mouseup() {\n dargPoint.value = ''\n}\n\nfunction resize() {\n cropInfo.value.width = props.defaultWidth\n cropInfo.value.height = props.defaultHeight\n x.value = 0\n y.value = 0\n}\n\ndocument.addEventListener('mouseup', mouseup)\ndocument.addEventListener('mousemove', mousemove)\n\nonMounted(() => {\n nextTick(() => {\n // 初始化位置\n initialValue.value.x\n = (containerBoxRef.value?.offsetWidth || 0) / 2 - cropInfo.value.width / 2\n initialValue.value.y\n = (containerBoxRef.value?.offsetHeight || 0) / 2\n - cropInfo.value.height / 2\n })\n})\n\nonUnmounted(() => {\n if (imageUrl.value) {\n URL.revokeObjectURL(imageUrl.value)\n }\n document.removeEventListener('mouseup', mouseup)\n document.removeEventListener('mousemove', mousemove)\n})\n\ndefineExpose({\n crop,\n resize,\n})\n</script>\n\n<template>\n <div ref=\"containerBoxRef\" :class=\"[ns.e('img-box')]\">\n <div v-if=\"errorMessage\" :class=\"[ns.e('error-message')]\">\n {{ errorMessage }}\n </div>\n <template v-else>\n <img\n ref=\"imgRef\"\n :class=\"[ns.e('image')]\"\n :src=\"imageUrl\"\n >\n <div\n ref=\"cropBoxRef\"\n :class=\"[ns.e('crop-tool-box')]\"\n :style=\"[\n sizeStyle,\n dargPoint\n ? `left: ${customStyle.left}px;top: ${customStyle.top}px`\n : style,\n ]\"\n >\n <div\n :class=\"[ns.e('top-left')]\"\n @mousedown=\"mousedown($event, 'top-left')\"\n />\n <div\n :class=\"[ns.e('top-right')]\"\n @mousedown=\"mousedown($event, 'top-right')\"\n />\n <div\n :class=\"[ns.e('bottom-right')]\"\n @mousedown=\"mousedown($event, 'bottom-right')\"\n />\n <div\n :class=\"[ns.e('bottom-left')]\"\n @mousedown=\"mousedown($event, 'bottom-left')\"\n />\n </div>\n </template>\n </div>\n</template>\n"],"names":["props","__props","startX","startY","startWidth","startHeight","ns","useNamespace","cropBoxRef","ref","containerBoxRef","imgRef","errorMessage","dargPoint","initialValue","x","y","cropInfo","width","defaultWidth","height","defaultHeight","useElementSize","imgWidth","style","useDraggable","containerElement","draggingElement","disabled","computed","value","exact","imageUrl","imgFile","URL","createObjectURL","watch","newFile","type","startsWith","ratio","naturalWidth","customStyle","position","left","top","sizeStyle","aspectRatio","zoomType","cssVarBlock","zoom","pixel","checkBoundaries","newWidth","newHeight","maxWidth","clientWidth","Infinity","maxHeight","clientHeight","Math","min","max","mousemove","e","deltaX","clientX","deltaY","clientY","Number","parseFloat","split","preventDefault","stopPropagation","mousedown","point","mouseup","document","addEventListener","onMounted","nextTick","offsetWidth","offsetHeight","onUnmounted","revokeObjectURL","removeEventListener","__expose","crop","async","img","backgroundColor","window","getComputedStyle","canvas","createElement","drawImage","cropCanvas","drawColor","useCanvas","offsetLeft","offsetTop","naturalHeight","resize"],"mappings":"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"}
|
1
|
+
{"version":3,"file":"photo-crop-tool.vue.cjs","sources":["../../../../../../packages/components/src/photo-crop-tool/src/photo-crop-tool.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { PropType } from 'vue'\nimport { useNamespace } from '@qxs-bns/hooks'\nimport { useCanvas } from './composables'\n\ndefineOptions({\n name: 'QxsPhotoCropTool',\n})\n\nconst props = defineProps({\n imgFile: {\n type: Object as PropType<File>,\n default: () => null,\n },\n aspectRatio: {\n type: String,\n default: () => '16 / 9',\n },\n defaultWidth: {\n type: Number,\n default: () => 320,\n },\n defaultHeight: {\n type: Number,\n default: () => 180,\n },\n /**\n * free 自由缩放\n * fixed 固定比例缩放\n */\n zoomType: {\n type: String,\n default: () => 'fixed',\n },\n})\nlet startX = 0\nlet startY = 0\nlet startWidth = 0\nlet startHeight = 0\n\nconst ns = useNamespace('photo-crop-tool')\n\nconst cropBoxRef = ref<HTMLElement | null>(null)\nconst containerBoxRef = ref<HTMLElement | null>(null)\nconst imgRef = ref<HTMLImageElement | null>(null)\nconst errorMessage = ref('')\nconst dargPoint = ref('')\nconst initialValue = ref({\n x: 0,\n y: 0,\n})\nconst cropInfo = ref({\n width: props.defaultWidth,\n height: props.defaultHeight,\n x: 0,\n y: 0,\n})\n\nconst { width, height } = useElementSize(cropBoxRef)\nconst { width: imgWidth } = useElementSize(imgRef)\n\nconst { x, y, style } = useDraggable(cropBoxRef, {\n containerElement: containerBoxRef,\n draggingElement: cropBoxRef,\n disabled: computed(() => !!dargPoint.value),\n exact: true,\n initialValue,\n})\n\nconst imageUrl = computed(() => {\n if (!props.imgFile) {\n return ''\n }\n return URL.createObjectURL(props.imgFile)\n})\n\nwatch(\n () => props.imgFile,\n (newFile: File | null) => {\n if (newFile && !newFile.type.startsWith('image/')) {\n errorMessage.value = '文件类型错误'\n }\n else {\n errorMessage.value = ''\n }\n },\n)\n\nconst ratio = computed(() => {\n return (imgRef.value?.naturalWidth || 0) / imgWidth.value\n})\n\nconst customStyle = computed(() => {\n const position = {\n left: 0,\n top: 0,\n }\n if (dargPoint.value === 'bottom-right') {\n position.left = cropInfo.value.x\n position.top = cropInfo.value.y\n }\n else if (dargPoint.value === 'top-left') {\n position.left = cropInfo.value.x - width.value\n position.top = cropInfo.value.y - height.value\n }\n else if (dargPoint.value === 'top-right') {\n position.top = cropInfo.value.y - height.value\n position.left = cropInfo.value.x\n }\n else if (dargPoint.value === 'bottom-left') {\n position.left = cropInfo.value.x - width.value\n position.top = cropInfo.value.y\n }\n return position\n})\n\nconst sizeStyle = computed(() => {\n const { aspectRatio } = props\n\n const style: {\n 'height'?: string\n 'width': string\n 'aspect-ratio'?: string\n 'top': string\n 'left': string\n } = {\n 'width': `${cropInfo.value.width || props.defaultWidth}`,\n 'height': `${cropInfo.value.height || props.defaultHeight}`,\n 'aspect-ratio': aspectRatio,\n 'top': `${customStyle.value.top}px`,\n 'left': `${customStyle.value.left}px`,\n }\n if (props.zoomType === 'free') {\n delete style['aspect-ratio']\n }\n else if (props.zoomType === 'fixed') {\n delete style.height\n }\n return ns.cssVarBlock(style)\n})\n\nfunction zoom(pixel: number) {\n return pixel * ratio.value\n}\nasync function crop(img: HTMLImageElement = imgRef.value!) {\n let backgroundColor = 'transparent'\n if (containerBoxRef.value) {\n backgroundColor = window.getComputedStyle(\n containerBoxRef.value,\n ).backgroundColor\n }\n const canvas = document.createElement('canvas')\n canvas.width = zoom(containerBoxRef.value?.clientWidth || 0)\n canvas.height = zoom(containerBoxRef.value?.clientHeight || 0)\n const { drawImage, cropCanvas, drawColor } = useCanvas(canvas)\n drawColor(0, 0, canvas.width, canvas.height, backgroundColor)\n drawImage(\n img,\n zoom(img.offsetLeft),\n zoom(img.offsetTop),\n img.naturalWidth,\n img.naturalHeight,\n )\n return await cropCanvas(\n zoom(x.value),\n zoom(y.value),\n zoom(width.value),\n zoom(height.value),\n )\n}\n\nfunction checkBoundaries(\n newWidth: number,\n newHeight: number,\n): { width: number, height: number } {\n const maxWidth = containerBoxRef.value?.clientWidth || Infinity\n const maxHeight = containerBoxRef.value?.clientHeight || Infinity\n\n return {\n width: Math.min(Math.max(newWidth, 0), maxWidth),\n height: Math.min(Math.max(newHeight, 0), maxHeight),\n }\n}\n\nfunction mousemove(e: MouseEvent) {\n const deltaX = e.clientX - startX\n const deltaY = e.clientY - startY\n\n if (dargPoint.value === 'bottom-right') {\n if (props.zoomType === 'free') {\n const { width, height } = checkBoundaries(\n startWidth + deltaX,\n startHeight + deltaY,\n )\n cropInfo.value.width = width\n cropInfo.value.height = height\n }\n else if (props.zoomType === 'fixed') {\n const aspectRatio\n = Number.parseFloat(props.aspectRatio.split(' / ')[0])\n / Number.parseFloat(props.aspectRatio.split(' / ')[1])\n let newWidth = startWidth + deltaX\n let newHeight = newWidth / aspectRatio\n const { width, height } = checkBoundaries(newWidth, newHeight)\n if (height > (containerBoxRef.value?.clientHeight || Infinity)) {\n newHeight = containerBoxRef.value?.clientHeight || Infinity\n newWidth = newHeight * aspectRatio\n }\n cropInfo.value.width = width\n cropInfo.value.height = height\n }\n }\n else if (dargPoint.value === 'top-left') {\n if (props.zoomType === 'free') {\n const { width, height } = checkBoundaries(\n startWidth - deltaX,\n startHeight - deltaY,\n )\n cropInfo.value.width = width\n cropInfo.value.height = height\n }\n else if (props.zoomType === 'fixed') {\n const aspectRatio\n = Number.parseFloat(props.aspectRatio.split(' / ')[0])\n / Number.parseFloat(props.aspectRatio.split(' / ')[1])\n let newWidth = startWidth - deltaX\n let newHeight = newWidth / aspectRatio\n const { width, height } = checkBoundaries(newWidth, newHeight)\n if (height > (containerBoxRef.value?.clientHeight || Infinity)) {\n newHeight = containerBoxRef.value?.clientHeight || Infinity\n newWidth = newHeight * aspectRatio\n }\n cropInfo.value.width = width\n cropInfo.value.height = height\n }\n x.value = customStyle.value.left\n y.value = customStyle.value.top\n }\n else if (dargPoint.value === 'top-right') {\n if (props.zoomType === 'free') {\n const { width, height } = checkBoundaries(\n startWidth + deltaX,\n startHeight - deltaY,\n )\n cropInfo.value.width = width\n cropInfo.value.height = height\n }\n else if (props.zoomType === 'fixed') {\n const aspectRatio\n = Number.parseFloat(props.aspectRatio.split(' / ')[0])\n / Number.parseFloat(props.aspectRatio.split(' / ')[1])\n let newWidth = startWidth + deltaX\n let newHeight = newWidth / aspectRatio\n const { width, height } = checkBoundaries(newWidth, newHeight)\n if (height > (containerBoxRef.value?.clientHeight || Infinity)) {\n newHeight = containerBoxRef.value?.clientHeight || Infinity\n newWidth = newHeight * aspectRatio\n }\n cropInfo.value.width = width\n cropInfo.value.height = height\n }\n x.value = customStyle.value.left\n y.value = customStyle.value.top\n }\n else if (dargPoint.value === 'bottom-left') {\n if (props.zoomType === 'free') {\n const { width, height } = checkBoundaries(\n startWidth - deltaX,\n startHeight + deltaY,\n )\n cropInfo.value.width = width\n cropInfo.value.height = height\n }\n else if (props.zoomType === 'fixed') {\n const aspectRatio\n = Number.parseFloat(props.aspectRatio.split(' / ')[0])\n / Number.parseFloat(props.aspectRatio.split(' / ')[1])\n let newWidth = startWidth - deltaX\n let newHeight = newWidth / aspectRatio\n const { width, height } = checkBoundaries(newWidth, newHeight)\n if (height > (containerBoxRef.value?.clientHeight || Infinity)) {\n newHeight = containerBoxRef.value?.clientHeight || Infinity\n newWidth = newHeight * aspectRatio\n }\n cropInfo.value.width = width\n cropInfo.value.height = height\n }\n x.value = customStyle.value.left\n y.value = customStyle.value.top\n }\n e.preventDefault()\n e.stopPropagation()\n}\n\nfunction mousedown(e: MouseEvent, point: string) {\n dargPoint.value = point\n startX = e.clientX\n startY = e.clientY\n startWidth = cropInfo.value.width\n startHeight = cropInfo.value.height\n\n if (point === 'bottom-right') {\n cropInfo.value.x = x.value\n cropInfo.value.y = y.value\n }\n else if (point === 'top-left') {\n cropInfo.value.x = x.value + width.value\n cropInfo.value.y = y.value + height.value\n }\n else if (point === 'top-right') {\n cropInfo.value.x = x.value\n cropInfo.value.y = y.value + height.value\n }\n else if (point === 'bottom-left') {\n cropInfo.value.x = x.value + width.value\n cropInfo.value.y = y.value\n }\n}\n\nfunction mouseup() {\n dargPoint.value = ''\n}\n\nfunction resize() {\n cropInfo.value.width = props.defaultWidth\n cropInfo.value.height = props.defaultHeight\n x.value = 0\n y.value = 0\n}\n\ndocument.addEventListener('mouseup', mouseup)\ndocument.addEventListener('mousemove', mousemove)\n\nonMounted(() => {\n nextTick(() => {\n // 初始化位置\n initialValue.value.x\n = (containerBoxRef.value?.offsetWidth || 0) / 2 - cropInfo.value.width / 2\n initialValue.value.y\n = (containerBoxRef.value?.offsetHeight || 0) / 2\n - cropInfo.value.height / 2\n })\n})\n\nonUnmounted(() => {\n if (imageUrl.value) {\n URL.revokeObjectURL(imageUrl.value)\n }\n document.removeEventListener('mouseup', mouseup)\n document.removeEventListener('mousemove', mousemove)\n})\n\ndefineExpose({\n crop,\n resize,\n})\n</script>\n\n<template>\n <div ref=\"containerBoxRef\" :class=\"[ns.e('img-box')]\">\n <div v-if=\"errorMessage\" :class=\"[ns.e('error-message')]\">\n {{ errorMessage }}\n </div>\n <template v-else>\n <img\n ref=\"imgRef\"\n :class=\"[ns.e('image')]\"\n :src=\"imageUrl\"\n >\n <div\n ref=\"cropBoxRef\"\n :class=\"[ns.e('crop-tool-box')]\"\n :style=\"[\n sizeStyle,\n dargPoint\n ? `left: ${customStyle.left}px;top: ${customStyle.top}px`\n : style,\n ]\"\n >\n <div\n :class=\"[ns.e('top-left')]\"\n @mousedown=\"mousedown($event, 'top-left')\"\n />\n <div\n :class=\"[ns.e('top-right')]\"\n @mousedown=\"mousedown($event, 'top-right')\"\n />\n <div\n :class=\"[ns.e('bottom-right')]\"\n @mousedown=\"mousedown($event, 'bottom-right')\"\n />\n <div\n :class=\"[ns.e('bottom-left')]\"\n @mousedown=\"mousedown($event, 'bottom-left')\"\n />\n </div>\n </template>\n </div>\n</template>\n"],"names":["props","__props","startX","startY","startWidth","startHeight","ns","useNamespace","cropBoxRef","ref","containerBoxRef","imgRef","errorMessage","dargPoint","initialValue","x","y","cropInfo","width","defaultWidth","height","defaultHeight","useElementSize","imgWidth","style","useDraggable","containerElement","draggingElement","disabled","computed","value","exact","imageUrl","imgFile","URL","createObjectURL","watch","newFile","type","startsWith","ratio","naturalWidth","customStyle","position","left","top","sizeStyle","aspectRatio","zoomType","cssVarBlock","zoom","pixel","checkBoundaries","newWidth","newHeight","maxWidth","clientWidth","Infinity","maxHeight","clientHeight","Math","min","max","mousemove","e","deltaX","clientX","deltaY","clientY","Number","parseFloat","split","preventDefault","stopPropagation","mousedown","point","mouseup","document","addEventListener","onMounted","nextTick","offsetWidth","offsetHeight","onUnmounted","revokeObjectURL","removeEventListener","__expose","crop","async","img","backgroundColor","window","getComputedStyle","canvas","createElement","drawImage","cropCanvas","drawColor","useCanvas","offsetLeft","offsetTop","naturalHeight","resize"],"mappings":"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"}
|
@@ -1,2 +1,2 @@
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("element-plus/es"),t=require("vue"),l=require("@element-plus/icons-vue"),a=require("@qxs-bns/hooks"),o=require("../../subject-type/src/subject-type.vue.cjs");const n={key:0,class:"flex-justify-between"},c={key:0,class:"has-set"},r={key:1,class:"flex flex-justify-end",
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("element-plus/es"),t=require("vue"),l=require("@element-plus/icons-vue"),a=require("@qxs-bns/hooks"),o=require("../../subject-type/src/subject-type.vue.cjs");const n={key:0,class:"flex-justify-between"},c={key:0,class:"has-set"},r={key:1,class:"flex flex-justify-end action-buttons"},i=!0;var d=t.defineComponent({name:"QxsSubjectAction",__name:"subject-action",props:{isEdit:{type:Boolean},isSet:{type:Boolean,default:!1},isKey:{type:Boolean,default:!1},answerCheckType:{type:Number,default:1},showOtherOption:{type:Boolean,default:!0},examAnswerRelationType:{type:Number,default:null},pageEnd:{type:Boolean,default:!1}},emits:["moveUp","moveDown","delete","save","edit","add","onShowRichText","setKey","setAnswerSetting"],setup(d,{emit:u}){const s=d,m=t.ref(s.isKey),p=t.ref(!1),f=u,V=t.ref(s.answerCheckType),k=a.useNamespace("subject-action"),x=[{value:2,label:"必须全部都是支持选项,方可下一步"},{value:1,label:"无需判断是否是支持选项"},{value:3,label:"包含全部支持选项,即可下一步"}],C=t.computed((()=>x.find((e=>e.value===V.value))?.label));function y(){p.value=!1,f("setAnswerSetting",V.value)}function v(e,t){f("add",e,t?s.examAnswerRelationType:null)}return(a,u)=>{const s=e.ElLink,N=e.ElPopover,h=e.ElCheckbox,w=e.ElIcon,b=e.ElButton,B=e.ElRadio,E=e.ElRadioGroup,g=e.ElDialog;return t.openBlock(),t.createElementBlock("div",{class:t.normalizeClass(t.unref(k).e("action-exam"))},[t.createElementVNode("div",{class:t.normalizeClass(["action flex flex-justify-between",[{active:d.isEdit}]])},[d.isEdit?(t.openBlock(),t.createElementBlock("div",n,[t.createVNode(N,{trigger:"click"},{reference:t.withCtx((()=>[t.createVNode(s,{type:"primary",class:"btn-margin"},{default:t.withCtx((()=>u[15]||(u[15]=[t.createTextVNode(" +在此题后加入新题 ")]))),_:1})])),default:t.withCtx((()=>[t.createVNode(o.default,{onSelect:v})])),_:1}),d.showOtherOption?(t.openBlock(),t.createBlock(s,{key:0,type:"primary",onClick:u[0]||(u[0]=e=>f("onShowRichText")),class:"btn-margin"},{default:t.withCtx((()=>u[16]||(u[16]=[t.createTextVNode(" +添加题目描述(图文) ")]))),_:1})):t.createCommentVNode("v-if",!0),d.showOtherOption?(t.openBlock(),t.createBlock(s,{key:1,type:"primary",onClick:u[1]||(u[1]=e=>p.value=!0),class:"btn-margin"},{default:t.withCtx((()=>u[17]||(u[17]=[t.createTextVNode(" 答题设置 ")]))),_:1})):t.createCommentVNode("v-if",!0),d.showOtherOption?(t.openBlock(),t.createBlock(h,{key:2,modelValue:t.unref(m),"onUpdate:modelValue":u[2]||(u[2]=e=>t.isRef(m)?m.value=e:null),label:"核心题",onChange:u[3]||(u[3]=e=>f("setKey",t.unref(m)))},null,8,["modelValue"])):t.createCommentVNode("v-if",!0)])):t.createCommentVNode("v-if",!0),t.createElementVNode("div",null,[d.isSet?(t.openBlock(),t.createElementBlock("div",c," *此题设置了跳题逻辑 ")):(t.openBlock(),t.createElementBlock("div",r,[d.isEdit?(t.openBlock(),t.createElementBlock(t.Fragment,{key:1},[t.createVNode(b,{class:"btn-margin",onClick:u[10]||(u[10]=e=>f("delete"))},{default:t.withCtx((()=>u[22]||(u[22]=[t.createTextVNode(" 删除 ")]))),_:1}),t.createVNode(b,{type:"primary",onClick:u[11]||(u[11]=e=>f("save"))},{default:t.withCtx((()=>u[23]||(u[23]=[t.createTextVNode(" 完成编辑 ")]))),_:1})],64)):(t.openBlock(),t.createElementBlock(t.Fragment,{key:0},[d.pageEnd?t.createCommentVNode("v-if",!0):(t.openBlock(),t.createBlock(h,{key:0,modelValue:t.unref(m),"onUpdate:modelValue":u[4]||(u[4]=e=>t.isRef(m)?m.value=e:null),label:"核心题",disabled:""},null,8,["modelValue"])),d.pageEnd?t.createCommentVNode("v-if",!0):(t.openBlock(),t.createBlock(h,{key:1,modelValue:i,"onUpdate:modelValue":u[5]||(u[5]=e=>i=e),label:t.unref(C),disabled:"",class:"checkbox-margin"},null,8,["label"])),d.pageEnd?t.createCommentVNode("v-if",!0):(t.openBlock(),t.createBlock(b,{key:2,class:"btn-margin",onClick:u[6]||(u[6]=e=>f("edit"))},{icon:t.withCtx((()=>[t.createVNode(w,null,{default:t.withCtx((()=>[t.createVNode(t.unref(l.Edit))])),_:1})])),default:t.withCtx((()=>[u[18]||(u[18]=t.createTextVNode(" 编辑 "))])),_:1})),t.createVNode(b,{class:"btn-margin",onClick:u[7]||(u[7]=e=>f("delete"))},{icon:t.withCtx((()=>[t.createVNode(w,null,{default:t.withCtx((()=>[t.createVNode(t.unref(l.Delete))])),_:1})])),default:t.withCtx((()=>[u[19]||(u[19]=t.createTextVNode(" 删除 "))])),_:1}),t.createVNode(b,{class:"btn-margin",onClick:u[8]||(u[8]=e=>f("moveUp"))},{icon:t.withCtx((()=>[t.createVNode(w,null,{default:t.withCtx((()=>[t.createVNode(t.unref(l.Top))])),_:1})])),default:t.withCtx((()=>[u[20]||(u[20]=t.createTextVNode(" 上移 "))])),_:1}),t.createVNode(b,{class:"btn-margin",onClick:u[9]||(u[9]=e=>f("moveDown"))},{icon:t.withCtx((()=>[t.createVNode(w,null,{default:t.withCtx((()=>[t.createVNode(t.unref(l.Bottom))])),_:1})])),default:t.withCtx((()=>[u[21]||(u[21]=t.createTextVNode(" 下移 "))])),_:1})],64))]))]),t.createVNode(g,{modelValue:t.unref(p),"onUpdate:modelValue":u[14]||(u[14]=e=>t.isRef(p)?p.value=e:null),title:"答题设置",class:"customize-dialog"},{footer:t.withCtx((()=>[t.createVNode(b,{class:"customize-button",type:"primary",plain:"",onClick:u[13]||(u[13]=e=>p.value=!1)},{default:t.withCtx((()=>u[24]||(u[24]=[t.createTextVNode(" 取消 ")]))),_:1}),t.createVNode(b,{class:"customize-button",type:"primary",plain:"",onClick:y},{default:t.withCtx((()=>u[25]||(u[25]=[t.createTextVNode(" 保存 ")]))),_:1})])),default:t.withCtx((()=>[t.createVNode(E,{modelValue:t.unref(V),"onUpdate:modelValue":u[12]||(u[12]=e=>t.isRef(V)?V.value=e:null),class:"vertical-radio-group"},{default:t.withCtx((()=>[(t.openBlock(),t.createElementBlock(t.Fragment,null,t.renderList(x,(e=>t.createVNode(B,{key:e.value,value:e.value},{default:t.withCtx((()=>[t.createTextVNode(t.toDisplayString(e.label),1)])),_:2},1032,["value"]))),64))])),_:1},8,["modelValue"])])),_:1},8,["modelValue"])],2)],2)}}});exports.default=d;
|
2
2
|
//# sourceMappingURL=subject-action.vue.cjs.map
|