问卷调整
This commit is contained in:
parent
2a6fb3d916
commit
904471d156
@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<!-- 版本号:每次发布时自动更新 -->
|
||||
<meta name="version" content="20251219-120015">
|
||||
<meta name="version" content="20251223-185504">
|
||||
<!-- HTML文件不缓存,但允许静态资源缓存 -->
|
||||
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
|
||||
<meta http-equiv="Pragma" content="no-cache">
|
||||
@ -14,7 +14,7 @@
|
||||
document.write(
|
||||
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
|
||||
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
|
||||
log=false
|
||||
var log = false;
|
||||
|
||||
// 版本检查:如果检测到新版本,清除缓存并刷新
|
||||
(function() {
|
||||
|
||||
@ -78,6 +78,10 @@ export const findAllZw = () => {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -19,6 +19,7 @@
|
||||
:mode="attrs.componentProps.mode"
|
||||
:title="attrs.label"
|
||||
:value="newValue ? newValue : undefined"
|
||||
:onPopupChange="handlePopupChange"
|
||||
@confirm="confirm"
|
||||
/>
|
||||
</view>
|
||||
@ -94,4 +95,14 @@ function confirm(e: any) {
|
||||
attrs.componentProps.ok(e, attrs);
|
||||
}
|
||||
}
|
||||
|
||||
// 处理弹窗状态变化
|
||||
function handlePopupChange(e: any) {
|
||||
if (
|
||||
attrs.componentProps.onPopupChange &&
|
||||
typeof attrs.componentProps.onPopupChange === "function"
|
||||
) {
|
||||
attrs.componentProps.onPopupChange(e);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -35,6 +35,7 @@
|
||||
v-model="pickerKey"
|
||||
@ok="ok"
|
||||
@change="change"
|
||||
@popupChange="handlePopupChange"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
@ -161,6 +162,16 @@ function change(e: any) {
|
||||
}
|
||||
}
|
||||
|
||||
// 处理弹窗状态变化
|
||||
function handlePopupChange(e: any) {
|
||||
if (
|
||||
attrs.componentProps.onPopupChange &&
|
||||
typeof attrs.componentProps.onPopupChange === "function"
|
||||
) {
|
||||
attrs.componentProps.onPopupChange(e);
|
||||
}
|
||||
}
|
||||
|
||||
const pickerValue = ref<any>("");
|
||||
|
||||
watchEffect(() => {
|
||||
|
||||
@ -19,7 +19,8 @@
|
||||
:rangeKey="rangeKey"
|
||||
:title="'选择'+ attrs.label"
|
||||
@confirm="confirm"
|
||||
v-bind="attrs.componentProps"
|
||||
:onPopupChange="handlePopupChange"
|
||||
v-bind="treeProps"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
@ -60,6 +61,12 @@
|
||||
const rangeKey = ref(attrs.componentProps && attrs.componentProps.rangeKey || '')
|
||||
const savaKey = ref(attrs.componentProps && attrs.componentProps.savaKey || '')
|
||||
|
||||
// 过滤掉 onPopupChange,避免重复传递
|
||||
const treeProps = computed(() => {
|
||||
const { onPopupChange, ...rest } = attrs.componentProps || {}
|
||||
return rest
|
||||
})
|
||||
|
||||
const range = computed({
|
||||
get() {
|
||||
if (attrs.componentProps && attrs.componentProps.range) {
|
||||
@ -106,6 +113,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 处理弹窗状态变化
|
||||
function handlePopupChange(e: any) {
|
||||
if (
|
||||
attrs.componentProps.onPopupChange &&
|
||||
typeof attrs.componentProps.onPopupChange === "function"
|
||||
) {
|
||||
attrs.componentProps.onPopupChange(e);
|
||||
}
|
||||
}
|
||||
|
||||
function hx(rangeData: any, data: any) {
|
||||
let valueList = data.split(',')
|
||||
for (const key in rangeData) {
|
||||
|
||||
@ -81,6 +81,11 @@ const props = defineProps({
|
||||
type: Array,
|
||||
default: [0],
|
||||
},
|
||||
// 支持通过 props 传递弹窗状态变化回调
|
||||
onPopupChange: {
|
||||
type: Function,
|
||||
default: null,
|
||||
},
|
||||
});
|
||||
|
||||
const emits = defineEmits([
|
||||
@ -132,6 +137,14 @@ function ok() {
|
||||
|
||||
function popupChange(e) {
|
||||
emits("popupChange", e);
|
||||
// 如果传递了回调函数,调用它
|
||||
if (props.onPopupChange) {
|
||||
try {
|
||||
props.onPopupChange(e);
|
||||
} catch (err) {
|
||||
console.error('[BasicPicker] 调用 onPopupChange 失败:', err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({ open, close });
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<uni-popup ref="popup" background-color="#fff" class="popup">
|
||||
<uni-popup ref="popup" background-color="#fff" class="popup" @change="popupChange">
|
||||
<view class="center flex-col wh-full">
|
||||
<view class="flex-row justify-between p-15">
|
||||
<view @click="close">
|
||||
@ -115,6 +115,11 @@ export default {
|
||||
defaultIndex: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
// 支持通过 props 传递弹窗状态变化回调
|
||||
onPopupChange: {
|
||||
type: Function,
|
||||
default: null,
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@ -156,6 +161,16 @@ export default {
|
||||
emits: ['close', 'canel', 'confirm', 'change'],
|
||||
// #endif
|
||||
methods: {
|
||||
popupChange(e) {
|
||||
// 如果传递了回调函数,调用它
|
||||
if (this.onPopupChange) {
|
||||
try {
|
||||
this.onPopupChange(e)
|
||||
} catch (err) {
|
||||
console.error('[DatetimePicker] 调用 onPopupChange 失败:', err)
|
||||
}
|
||||
}
|
||||
},
|
||||
init() {
|
||||
this.innerValue = this.correctValue(this.value)
|
||||
this.updateColumnValue(this.innerValue)
|
||||
|
||||
@ -118,6 +118,11 @@ export default {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 支持通过 props 传递弹窗状态变化回调
|
||||
onPopupChange: {
|
||||
type: Function,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@ -130,9 +135,25 @@ export default {
|
||||
methods: {
|
||||
_show() {
|
||||
this.showTree = true
|
||||
// 触发弹窗打开事件
|
||||
if (this.onPopupChange && typeof this.onPopupChange === 'function') {
|
||||
try {
|
||||
this.onPopupChange({ show: true, type: 'bottom' })
|
||||
} catch (err) {
|
||||
console.error('[BasicTree] 调用 onPopupChange 失败:', err)
|
||||
}
|
||||
}
|
||||
},
|
||||
_hide() {
|
||||
this.showTree = false
|
||||
// 触发弹窗关闭事件
|
||||
if (this.onPopupChange && typeof this.onPopupChange === 'function') {
|
||||
try {
|
||||
this.onPopupChange({ show: false, type: 'bottom' })
|
||||
} catch (err) {
|
||||
console.error('[BasicTree] 调用 onPopupChange 失败:', err)
|
||||
}
|
||||
}
|
||||
},
|
||||
_cancel() {
|
||||
this._hide()
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
<text class="loading-text">{{ loadingText }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<scroll-view scroll-y class="form-scroll" :enable-back-to-top="false">
|
||||
<scroll-view scroll-y class="form-scroll" :class="{ 'full-height': hideBottomBtn }" :enable-back-to-top="false">
|
||||
<view class="form-container">
|
||||
<!-- 积分标准区域 -->
|
||||
<view class="section">
|
||||
@ -148,13 +148,11 @@
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<template #bottom>
|
||||
<view class="fixed-bottom">
|
||||
<button class="submit-btn" @click="handleSubmit" :disabled="submitting">
|
||||
{{ submitting ? '保存中...' : '保存' }}
|
||||
</button>
|
||||
</view>
|
||||
</template>
|
||||
<view class="bottom-btn-area" :class="{ 'hide-bottom': hideBottomBtn }">
|
||||
<button class="save-button" @click="handleSubmit" :disabled="submitting">
|
||||
{{ submitting ? '保存中...' : '保存' }}
|
||||
</button>
|
||||
</view>
|
||||
</BasicLayout>
|
||||
<view v-else class="edit-content-wrapper">
|
||||
<view v-if="loading" class="loading-mask">
|
||||
@ -326,6 +324,15 @@ import CertificateUpload from "@/components/CertificateUpload/index.vue";
|
||||
// 独立页面使用;可根据参数隐藏保存按钮(查看模式)
|
||||
const showSaveButton = ref(true);
|
||||
|
||||
// 是否隐藏底部按钮
|
||||
const hideBottomBtn = ref(false);
|
||||
|
||||
// 处理选择器弹窗状态变化
|
||||
const handlePickerPopupChange = (e: any) => {
|
||||
// e.show 为 true 表示弹窗打开,false 表示关闭
|
||||
hideBottomBtn.value = e.show;
|
||||
};
|
||||
|
||||
const formData = reactive<any>({
|
||||
id: '',
|
||||
jfTypeId: '',
|
||||
@ -1092,7 +1099,8 @@ const formSchema = computed(() => {
|
||||
selectParent: false,
|
||||
defaultExpandLevel: 0,
|
||||
confirmColor: "#3b82f6",
|
||||
ok: handleJfTypeTreeConfirm
|
||||
ok: handleJfTypeTreeConfirm,
|
||||
onPopupChange: handlePickerPopupChange
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -1150,7 +1158,8 @@ const assessmentSchema = computed(() => {
|
||||
range: hjlxOptions.value,
|
||||
rangeKey: "label",
|
||||
savaKey: "value",
|
||||
placeholder: '请选择获奖类型'
|
||||
placeholder: '请选择获奖类型',
|
||||
onPopupChange: handlePickerPopupChange
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -1174,7 +1183,8 @@ const assessmentSchema = computed(() => {
|
||||
mode: "date",
|
||||
minDate: dayjs('1950-01-01').valueOf(),
|
||||
maxDate: dayjs().valueOf(),
|
||||
placeholder: '请选择获奖时间'
|
||||
placeholder: '请选择获奖时间',
|
||||
onPopupChange: handlePickerPopupChange
|
||||
}
|
||||
},
|
||||
// 根据 showStudentAward 动态添加获奖名单和获奖人数字段
|
||||
@ -1206,6 +1216,7 @@ const assessmentSchema = computed(() => {
|
||||
rangeKey: "label",
|
||||
savaKey: "value",
|
||||
placeholder: '请选择类别',
|
||||
onPopupChange: handlePickerPopupChange,
|
||||
ok: () => {
|
||||
if (formData.category && scoreConfig.value) {
|
||||
checkGradeFieldVisibility(scoreConfig.value, formData.category);
|
||||
@ -1222,7 +1233,8 @@ const assessmentSchema = computed(() => {
|
||||
range: defaultLevels,
|
||||
rangeKey: "label",
|
||||
savaKey: "value",
|
||||
placeholder: '请选择级别'
|
||||
placeholder: '请选择级别',
|
||||
onPopupChange: handlePickerPopupChange
|
||||
}
|
||||
}
|
||||
];
|
||||
@ -1241,7 +1253,8 @@ const assessmentSchema = computed(() => {
|
||||
],
|
||||
rangeKey: "label",
|
||||
savaKey: "value",
|
||||
placeholder: '请选择等级'
|
||||
placeholder: '请选择等级',
|
||||
onPopupChange: handlePickerPopupChange
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -1754,8 +1767,13 @@ onLoad(async (options: any) => {
|
||||
<style scoped lang="scss">
|
||||
.form-scroll {
|
||||
flex: 1;
|
||||
height: calc(100vh - 120rpx);
|
||||
height: calc(100vh - 140rpx);
|
||||
max-height: 100vh;
|
||||
transition: height 0.3s ease;
|
||||
}
|
||||
|
||||
.form-scroll.full-height {
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.edit-content-wrapper {
|
||||
@ -1809,38 +1827,46 @@ onLoad(async (options: any) => {
|
||||
}
|
||||
}
|
||||
|
||||
.fixed-bottom {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: #ffffff;
|
||||
padding: 24rpx;
|
||||
box-shadow: 0 -4rpx 16rpx rgba(0, 0, 0, 0.08);
|
||||
z-index: 100;
|
||||
|
||||
|
||||
.bottom-btn-area {
|
||||
padding: 20rpx 30rpx;
|
||||
padding-bottom: calc(20rpx + constant(safe-area-inset-bottom));
|
||||
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
|
||||
background: #fff;
|
||||
border-top: 1rpx solid #e5e5e5;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&.hide-bottom {
|
||||
display: none !important;
|
||||
height: 0 !important;
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
border: none !important;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
.save-button {
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
line-height: 88rpx;
|
||||
background: #3b82f6;
|
||||
color: #ffffff;
|
||||
height: 80rpx;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: #fff;
|
||||
font-size: 30rpx;
|
||||
font-weight: 500;
|
||||
border-radius: 40rpx;
|
||||
border: none;
|
||||
border-radius: 16rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
box-shadow: 0 4rpx 16rpx rgba(59, 130, 246, 0.3);
|
||||
transition: all 0.3s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&:disabled {
|
||||
background: #9ca3af;
|
||||
box-shadow: none;
|
||||
opacity: 0.6;
|
||||
background: #ccc;
|
||||
}
|
||||
|
||||
&:active:not(:disabled) {
|
||||
transform: scale(0.98);
|
||||
background: #1d4ed8;
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
<text class="loading-text">{{ loadingText }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<scroll-view scroll-y class="form-scroll">
|
||||
<scroll-view scroll-y class="form-scroll" :class="{ 'full-height': hideBottomBtn }" :enable-back-to-top="false">
|
||||
<view class="form-container">
|
||||
<!-- 积分标准区域 -->
|
||||
<view class="section">
|
||||
@ -165,7 +165,7 @@
|
||||
</scroll-view>
|
||||
|
||||
<!-- 固定在底部的按钮组 -->
|
||||
<view class="fixed-bottom">
|
||||
<view class="fixed-bottom" :class="{ 'hide-bottom': hideBottomBtn }">
|
||||
<view class="button-group">
|
||||
<button class="save-btn" @click="handleSave" :disabled="saving || submitting">
|
||||
{{ saving ? '保存中...' : '暂存' }}
|
||||
@ -250,6 +250,7 @@ const loading = ref(false); // 页面加载状态
|
||||
const loadingText = ref('加载中...'); // 加载提示文本
|
||||
const isResubmit = ref(false); // 是否为重新提交模式
|
||||
const jfId = ref(''); // 积分ID(重新提交时使用)
|
||||
const hideBottomBtn = ref(false); // 控制底部按钮区域显示/隐藏
|
||||
// 用于强制更新表单的 key
|
||||
const formSchemaKey = ref(0);
|
||||
// 用于强制更新获奖情况表单的 key
|
||||
@ -537,6 +538,12 @@ function findNodeById(nodes: any[], id: string, path: string[] = []): { node: an
|
||||
// 选中的业绩类别显示文本(用于回显)
|
||||
const selectedJfTypeText = ref('');
|
||||
|
||||
// 处理选择器弹窗状态变化
|
||||
const handlePickerPopupChange = (e: any) => {
|
||||
// e.show 为 true 表示弹窗打开,false 表示关闭
|
||||
hideBottomBtn.value = e.show;
|
||||
};
|
||||
|
||||
// 初始化回显:根据 formData.jfTypeId 设置显示文本
|
||||
const initJfTypeDisplay = () => {
|
||||
if (formData.jfTypeId && jfTypeTree.value.length > 0) {
|
||||
@ -1018,7 +1025,8 @@ const formSchema = computed(() => {
|
||||
selectParent: false, // 只能选择叶子节点
|
||||
defaultExpandLevel: 0, // 默认不展开
|
||||
confirmColor: "#3b82f6",
|
||||
ok: handleJfTypeTreeConfirm
|
||||
ok: handleJfTypeTreeConfirm,
|
||||
onPopupChange: handlePickerPopupChange
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -1067,7 +1075,8 @@ const assessmentSchema = computed(() => {
|
||||
range: hjlxOptions.value,
|
||||
rangeKey: "label",
|
||||
savaKey: "value",
|
||||
placeholder: '请选择获奖类型'
|
||||
placeholder: '请选择获奖类型',
|
||||
onPopupChange: handlePickerPopupChange
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -1091,7 +1100,8 @@ const assessmentSchema = computed(() => {
|
||||
mode: "date",
|
||||
minDate: dayjs('1950-01-01').valueOf(),
|
||||
maxDate: dayjs().valueOf(),
|
||||
placeholder: '请选择获奖时间'
|
||||
placeholder: '请选择获奖时间',
|
||||
onPopupChange: handlePickerPopupChange
|
||||
}
|
||||
},
|
||||
// 根据 showStudentAward 动态添加获奖名单和获奖人数字段
|
||||
@ -1123,6 +1133,7 @@ const assessmentSchema = computed(() => {
|
||||
rangeKey: "label",
|
||||
savaKey: "value",
|
||||
placeholder: '请选择类别',
|
||||
onPopupChange: handlePickerPopupChange,
|
||||
ok: () => {
|
||||
// 选择类别后,检查是否需要显示等级字段
|
||||
if (formData.category && scoreConfig.value) {
|
||||
@ -1140,7 +1151,8 @@ const assessmentSchema = computed(() => {
|
||||
range: defaultLevels,
|
||||
rangeKey: "label",
|
||||
savaKey: "value",
|
||||
placeholder: '请选择级别'
|
||||
placeholder: '请选择级别',
|
||||
onPopupChange: handlePickerPopupChange
|
||||
}
|
||||
}
|
||||
];
|
||||
@ -1160,7 +1172,8 @@ const assessmentSchema = computed(() => {
|
||||
],
|
||||
rangeKey: "label",
|
||||
savaKey: "value",
|
||||
placeholder: '请选择等级'
|
||||
placeholder: '请选择等级',
|
||||
onPopupChange: handlePickerPopupChange
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -1903,6 +1916,10 @@ onLoad(async (options: any) => {
|
||||
.form-scroll {
|
||||
flex: 1;
|
||||
height: calc(100vh - 120rpx);
|
||||
|
||||
&.full-height {
|
||||
height: 100vh;
|
||||
}
|
||||
}
|
||||
|
||||
.form-container {
|
||||
@ -1952,6 +1969,12 @@ onLoad(async (options: any) => {
|
||||
box-shadow: 0 -4rpx 16rpx rgba(0, 0, 0, 0.08);
|
||||
z-index: 1;
|
||||
|
||||
&.hide-bottom {
|
||||
display: none !important;
|
||||
height: 0 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
display: flex;
|
||||
gap: 24rpx;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<BasicLayout v-if="showSaveButton">
|
||||
<scroll-view scroll-y class="form-scroll" :enable-back-to-top="false">
|
||||
<scroll-view scroll-y class="form-scroll" :class="{ 'full-height': hideBottomBtn }" :enable-back-to-top="false">
|
||||
<view class="form-container">
|
||||
<!-- 积分标准区域 -->
|
||||
<view class="section">
|
||||
@ -134,7 +134,7 @@
|
||||
</scroll-view>
|
||||
|
||||
<template #bottom>
|
||||
<view class="fixed-bottom">
|
||||
<view class="fixed-bottom" :class="{ 'hide-bottom': hideBottomBtn }">
|
||||
<button class="submit-btn" @click="handleSubmit" :disabled="submitting">
|
||||
{{ submitting ? '保存中...' : '保存' }}
|
||||
</button>
|
||||
@ -310,6 +310,7 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
const emit = defineEmits<{
|
||||
(e: 'saved'): void;
|
||||
(e: 'loaded'): void;
|
||||
(e: 'popup-change', show: boolean): void;
|
||||
}>();
|
||||
|
||||
// 表单数据(暴露给父组件访问)
|
||||
@ -365,6 +366,16 @@ const formSchemaKey = ref(0);
|
||||
const assessmentSchemaKey = ref(0);
|
||||
// 证书上传组件引用
|
||||
const certificateUploadRef = ref<any>(null);
|
||||
// 控制底部按钮区域显示/隐藏
|
||||
const hideBottomBtn = ref(false);
|
||||
|
||||
// 处理选择器弹窗状态变化
|
||||
const handlePickerPopupChange = (e: any) => {
|
||||
// e.show 为 true 表示弹窗打开,false 表示关闭
|
||||
hideBottomBtn.value = e.show;
|
||||
// 向父组件发送弹窗状态变化事件
|
||||
emit('popup-change', e.show);
|
||||
};
|
||||
|
||||
// 防抖更新表单 key
|
||||
let updateSchemaKeyTimer: any = null;
|
||||
@ -1043,7 +1054,8 @@ const assessmentSchema = computed(() => {
|
||||
range: hjlxOptions.value,
|
||||
rangeKey: "label",
|
||||
savaKey: "value",
|
||||
placeholder: '请选择获奖类型'
|
||||
placeholder: '请选择获奖类型',
|
||||
onPopupChange: handlePickerPopupChange
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -1067,7 +1079,8 @@ const assessmentSchema = computed(() => {
|
||||
mode: "date",
|
||||
minDate: dayjs('1950-01-01').valueOf(),
|
||||
maxDate: dayjs().valueOf(),
|
||||
placeholder: '请选择获奖时间'
|
||||
placeholder: '请选择获奖时间',
|
||||
onPopupChange: handlePickerPopupChange
|
||||
}
|
||||
},
|
||||
// 根据 showStudentAward 动态添加获奖名单和获奖人数字段
|
||||
@ -1099,6 +1112,7 @@ const assessmentSchema = computed(() => {
|
||||
rangeKey: "label",
|
||||
savaKey: "value",
|
||||
placeholder: '请选择类别',
|
||||
onPopupChange: handlePickerPopupChange,
|
||||
ok: () => {
|
||||
if (formData.category && scoreConfig.value) {
|
||||
checkGradeFieldVisibility(scoreConfig.value, formData.category);
|
||||
@ -1115,7 +1129,8 @@ const assessmentSchema = computed(() => {
|
||||
range: defaultLevels,
|
||||
rangeKey: "label",
|
||||
savaKey: "value",
|
||||
placeholder: '请选择级别'
|
||||
placeholder: '请选择级别',
|
||||
onPopupChange: handlePickerPopupChange
|
||||
}
|
||||
}
|
||||
];
|
||||
@ -1134,7 +1149,8 @@ const assessmentSchema = computed(() => {
|
||||
],
|
||||
rangeKey: "label",
|
||||
savaKey: "value",
|
||||
placeholder: '请选择等级'
|
||||
placeholder: '请选择等级',
|
||||
onPopupChange: handlePickerPopupChange
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -1683,6 +1699,10 @@ defineExpose({
|
||||
flex: 1;
|
||||
height: calc(100vh - 120rpx);
|
||||
max-height: 100vh;
|
||||
|
||||
&.full-height {
|
||||
height: 100vh;
|
||||
}
|
||||
}
|
||||
|
||||
.edit-content-wrapper {
|
||||
@ -1745,6 +1765,12 @@ defineExpose({
|
||||
padding: 24rpx;
|
||||
box-shadow: 0 -4rpx 16rpx rgba(0, 0, 0, 0.08);
|
||||
z-index: 100;
|
||||
|
||||
&.hide-bottom {
|
||||
display: none !important;
|
||||
height: 0 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<BasicLayout>
|
||||
<!-- 统一的滚动容器,包含编辑组件和流程组件 -->
|
||||
<scroll-view scroll-y class="unified-scroll">
|
||||
<scroll-view scroll-y class="unified-scroll" :class="{ 'full-height': hideBottomBtn }">
|
||||
<!-- 引入编辑组件(不包含滚动) -->
|
||||
<JfEdit v-if="isLoginReady" ref="jfEditRef" :jf-id="jfId" @saved="handleDataSaved" @loaded="handleJfEditLoaded" />
|
||||
<JfEdit v-if="isLoginReady" ref="jfEditRef" :jf-id="jfId" @saved="handleDataSaved" @loaded="handleJfEditLoaded" @popup-change="handlePickerPopupChange" />
|
||||
|
||||
<!-- 审批流程展示 -->
|
||||
<view class="flow-section" v-if="jfId">
|
||||
@ -12,26 +12,28 @@
|
||||
</scroll-view>
|
||||
|
||||
<template #bottom>
|
||||
<YwConfirm
|
||||
v-if="showButton"
|
||||
:spApi="wrappedJfSpApi"
|
||||
:stopApi="wrappedJfStopApi"
|
||||
:transferApi="wrappedJfTransferApi"
|
||||
:params="spParams"
|
||||
:autoToMessage="false"
|
||||
:showXt="false"
|
||||
:showReject="!isYiban"
|
||||
:showTransfer="false"
|
||||
:showApprove="!isYiban"
|
||||
:showReturn="false"
|
||||
:showStop="true"
|
||||
:showXtDk="false"
|
||||
approveText="通过"
|
||||
@submit="handleSubmit"
|
||||
@reject="handleReject"
|
||||
@transfer="handleTransfer"
|
||||
@stop="handleStop"
|
||||
/>
|
||||
<view :class="{ 'hide-bottom': hideBottomBtn }">
|
||||
<YwConfirm
|
||||
v-if="showButton"
|
||||
:spApi="wrappedJfSpApi"
|
||||
:stopApi="wrappedJfStopApi"
|
||||
:transferApi="wrappedJfTransferApi"
|
||||
:params="spParams"
|
||||
:autoToMessage="false"
|
||||
:showXt="false"
|
||||
:showReject="!isYiban"
|
||||
:showTransfer="false"
|
||||
:showApprove="!isYiban"
|
||||
:showReturn="false"
|
||||
:showStop="true"
|
||||
:showXtDk="false"
|
||||
approveText="通过"
|
||||
@submit="handleSubmit"
|
||||
@reject="handleReject"
|
||||
@transfer="handleTransfer"
|
||||
@stop="handleStop"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<!-- 遮罩层 -->
|
||||
@ -64,6 +66,8 @@ const showButton = ref<boolean>(false);
|
||||
const isLoginReady = ref<boolean>(false); // 登录是否准备就绪
|
||||
// 编辑组件的引用,用于获取表单数据
|
||||
const jfEditRef = ref<any>(null);
|
||||
// 控制底部按钮区域显示/隐藏
|
||||
const hideBottomBtn = ref(false);
|
||||
// 遮罩层状态
|
||||
const loading = ref<boolean>(false);
|
||||
const loadingText = ref<string>("处理中...");
|
||||
@ -401,6 +405,11 @@ const wrappedJfStopApi = async (params: any) => {
|
||||
}
|
||||
};
|
||||
|
||||
// 处理选择器弹窗状态变化
|
||||
const handlePickerPopupChange = (show: boolean) => {
|
||||
hideBottomBtn.value = show;
|
||||
};
|
||||
|
||||
// 处理编辑组件数据加载完成
|
||||
const handleJfEditLoaded = () => {
|
||||
jfEditLoaded.value = true;
|
||||
@ -553,6 +562,10 @@ onLoad(async (options: any) => {
|
||||
flex: 1;
|
||||
height: calc(100vh - 120rpx);
|
||||
overflow-y: auto;
|
||||
|
||||
&.full-height {
|
||||
height: 100vh;
|
||||
}
|
||||
}
|
||||
|
||||
.flow-section {
|
||||
@ -626,5 +639,12 @@ onLoad(async (options: any) => {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
// 隐藏底部按钮区域
|
||||
.hide-bottom {
|
||||
display: none !important;
|
||||
height: 0 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@ -300,7 +300,7 @@
|
||||
<view v-if="analysisResult" class="analysis-result">
|
||||
<view class="analysis-header">
|
||||
<u-icon name="file-text" size="20" color="#409EFF"></u-icon>
|
||||
<text class="analysis-title">AI分析报告</text>
|
||||
<text class="analysis-title">AI数字分析</text>
|
||||
</view>
|
||||
<view class="analysis-content">
|
||||
<text class="analysis-text">{{ analysisResult }}</text>
|
||||
|
||||
@ -306,7 +306,7 @@
|
||||
<view v-if="analysisResult" class="analysis-result">
|
||||
<view class="analysis-header">
|
||||
<u-icon name="file-text" size="20" color="#409EFF"></u-icon>
|
||||
<text class="analysis-title">AI分析报告</text>
|
||||
<text class="analysis-title">AI数字分析</text>
|
||||
</view>
|
||||
<view class="analysis-content">
|
||||
<text class="analysis-text">{{ analysisResult }}</text>
|
||||
|
||||
@ -284,29 +284,12 @@
|
||||
<text class="success-time">{{ formatTime(new Date()) }}</text>
|
||||
<text class="success-tip">您已成功提交问卷</text>
|
||||
|
||||
<!-- 添加AI分析按钮 -->
|
||||
<button v-if="!analysisResult && !analyzing" @click="analyzeWithAI" class="ai-analyze-btn">
|
||||
<!-- 查看AI分析报告按钮 -->
|
||||
<button @click="viewAIAnalysisReport" class="ai-analyze-btn">
|
||||
<u-icon name="file-text" size="18" color="#fff" style="margin-right: 8rpx;"></u-icon>
|
||||
AI智能分析
|
||||
查看AI分析报告
|
||||
</button>
|
||||
|
||||
<!-- 分析中状态 -->
|
||||
<view v-if="analyzing" class="analyzing-container">
|
||||
<u-loading-icon mode="spinner" size="24" color="#409EFF"></u-loading-icon>
|
||||
<text class="analyzing-text">AI分析中,请稍候...</text>
|
||||
</view>
|
||||
|
||||
<!-- 分析结果 -->
|
||||
<view v-if="analysisResult" class="analysis-result">
|
||||
<view class="analysis-header">
|
||||
<u-icon name="file-text" size="20" color="#409EFF"></u-icon>
|
||||
<text class="analysis-title">AI分析报告</text>
|
||||
</view>
|
||||
<view class="analysis-content">
|
||||
<text class="analysis-text">{{ analysisResult }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<button @click="goBack" class="back-btn">返回</button>
|
||||
</view>
|
||||
</view>
|
||||
@ -327,6 +310,13 @@
|
||||
<u-icon name="info-circle" size="80" color="#409EFF"></u-icon>
|
||||
<text class="already-filled-title">已填写</text>
|
||||
<text class="already-filled-subtitle">您已经填写过此问卷</text>
|
||||
|
||||
<!-- 查看AI分析报告按钮 -->
|
||||
<button @click="viewAIAnalysisReport" class="ai-analyze-btn">
|
||||
<u-icon name="file-text" size="18" color="#fff" style="margin-right: 8rpx;"></u-icon>
|
||||
查看AI分析报告
|
||||
</button>
|
||||
|
||||
<button @click="goBack" class="back-btn">返回</button>
|
||||
</view>
|
||||
</view>
|
||||
@ -351,8 +341,7 @@ import {
|
||||
questionnaireCheckPermissionApi,
|
||||
questionnaireQuestionFindPageApi,
|
||||
questionnaireAnswerSaveApi,
|
||||
questionnaireAnswerFindByUserApi,
|
||||
questionnaireAnalyzeWithAIApi
|
||||
questionnaireAnswerFindByUserApi
|
||||
} from '@/api/base/wjApi';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
import { attachmentUpload } from '@/api/system/upload';
|
||||
@ -363,6 +352,7 @@ const userStore = useUserStore();
|
||||
// 页面参数
|
||||
const options = ref<any>({});
|
||||
const questionnaireId = ref('');
|
||||
const xxtsId = ref<string>(""); // 消息推送表ID(用于更新待办状态)
|
||||
const openId = ref<string>(""); // 微信 openId
|
||||
const loading = ref(true);
|
||||
const submitting = ref(false); // 提交中状态
|
||||
@ -392,9 +382,8 @@ const fileUploadData = reactive<Record<string, {
|
||||
// 压缩配置
|
||||
const compressConfig = ref(COMPRESS_PRESETS.high);
|
||||
|
||||
// AI分析相关
|
||||
const analyzing = ref(false);
|
||||
const analysisResult = ref('');
|
||||
// 提交批次ID,用于查看AI分析报告
|
||||
const submitId = ref<string>('');
|
||||
|
||||
// 签名组件相关
|
||||
const signCompRef = ref<any>(null);
|
||||
@ -406,6 +395,7 @@ const currentSignatureQuestionId = ref<string>(""); // 当前正在签名的题
|
||||
onLoad(async (params) => {
|
||||
options.value = params;
|
||||
openId.value = params?.openId || '';
|
||||
xxtsId.value = params?.id || ''; // 获取 xxts 表的 id
|
||||
|
||||
// 如果有 openId,先进行认证
|
||||
if (openId.value) {
|
||||
@ -1062,10 +1052,20 @@ const doSubmitQuestionnaire = async () => {
|
||||
submitParams.signatureImage = sign_file.value;
|
||||
}
|
||||
|
||||
// 如果有 xxtsId,添加到提交参数中(用于更新待办状态)
|
||||
if (xxtsId.value) {
|
||||
submitParams.xxtsId = xxtsId.value;
|
||||
}
|
||||
|
||||
// 提交答案
|
||||
const result = await questionnaireAnswerSaveApi(submitParams);
|
||||
|
||||
if (result && result.resultCode === 1) {
|
||||
// 保存 submitId(从返回结果中获取)
|
||||
const resultData = result.result || result.data || {};
|
||||
if (resultData.submitId) {
|
||||
submitId.value = resultData.submitId;
|
||||
}
|
||||
currentStep.value = 'success';
|
||||
} else {
|
||||
throw new Error(result?.message || '提交失败');
|
||||
@ -1094,69 +1094,14 @@ const formatTime = (time: string | Date) => {
|
||||
});
|
||||
};
|
||||
|
||||
// AI分析函数
|
||||
const analyzeWithAI = async () => {
|
||||
try {
|
||||
analyzing.value = true;
|
||||
analysisResult.value = '';
|
||||
|
||||
// 构造发送给AI的问卷数据,包含所有分页的题目
|
||||
const allQuestions: any[] = [];
|
||||
pageList.value.forEach(page => {
|
||||
allQuestions.push(...page.questions);
|
||||
});
|
||||
|
||||
const questionnaireData = {
|
||||
questionnaireId: questionnaireId.value,
|
||||
title: questionnaireInfo.value?.title,
|
||||
description: questionnaireInfo.value?.description,
|
||||
questions: allQuestions.map((q: any) => {
|
||||
let answerValue = answers[q.id]?.value;
|
||||
|
||||
// 处理不同类型的答案格式
|
||||
if (q.questionType === 'CHECKBOX' && Array.isArray(answerValue)) {
|
||||
answerValue = answerValue.join(',');
|
||||
} else if (q.questionType === 'FILE') {
|
||||
const uploadData = fileUploadData[q.id];
|
||||
const imageUrls = (uploadData?.imageList || []).filter(img => img.url).map(img => img.url);
|
||||
const fileUrls = (uploadData?.fileList || []).filter(file => file.url).map(file => file.url);
|
||||
answerValue = [...imageUrls, ...fileUrls].join(',');
|
||||
} else if (q.questionType === 'VIDEO') {
|
||||
const uploadData = fileUploadData[q.id];
|
||||
const videoUrls = (uploadData?.videoList || []).filter(video => video.url).map(video => video.url);
|
||||
answerValue = videoUrls.join(',');
|
||||
} else if (q.questionType === 'SIGNATURE') {
|
||||
answerValue = answerValue ? '[已签名]' : '[未签名]';
|
||||
}
|
||||
|
||||
// 获取分页名称和排序
|
||||
const pageName = q.pageName || '第一部分';
|
||||
const pageSortOrder = q.pageSortOrder !== undefined ? q.pageSortOrder : 0;
|
||||
|
||||
return {
|
||||
content: q.questionContent,
|
||||
type: q.questionType,
|
||||
answer: answerValue || '[未填写]',
|
||||
pageName: pageName,
|
||||
pageSortOrder: pageSortOrder
|
||||
};
|
||||
})
|
||||
};
|
||||
|
||||
// 调用后端AI分析接口
|
||||
const response = await questionnaireAnalyzeWithAIApi(questionnaireData);
|
||||
|
||||
if (response && response.resultCode === 1) {
|
||||
analysisResult.value = response.result || response.data || '分析完成';
|
||||
} else {
|
||||
throw new Error(response?.message || 'AI分析失败');
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('AI分析失败:', error);
|
||||
uni.showToast({ title: error.message || 'AI分析失败,请稍后重试', icon: 'none', duration: 2000 });
|
||||
} finally {
|
||||
analyzing.value = false;
|
||||
}
|
||||
// 查看AI分析报告
|
||||
const viewAIAnalysisReport = () => {
|
||||
// 获取当前用户ID(参考 wjDetail.vue)
|
||||
const currentUserId = userStore.userdata?.id || userStore.userdata?.userId || '';
|
||||
// 跳转到 wjEvaluatedl.vue,传递 questionnaireId 和 userId(参考 wjDetail.vue)
|
||||
uni.navigateTo({
|
||||
url: `/pages/view/routine/wj/wjEvaluatedl?questionnaireId=${questionnaireId.value}&userId=${currentUserId}`
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
@ -1687,57 +1632,6 @@ const analyzeWithAI = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
.analyzing-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 30rpx;
|
||||
padding: 30rpx;
|
||||
background: #f5f7fa;
|
||||
border-radius: 16rpx;
|
||||
|
||||
.analyzing-text {
|
||||
margin-left: 20rpx;
|
||||
font-size: 28rpx;
|
||||
color: #409EFF;
|
||||
}
|
||||
}
|
||||
|
||||
.analysis-result {
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 30rpx;
|
||||
margin-bottom: 30rpx;
|
||||
text-align: left;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
|
||||
max-width: 100%;
|
||||
|
||||
.analysis-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 20rpx;
|
||||
padding-bottom: 16rpx;
|
||||
border-bottom: 2rpx solid #eee;
|
||||
|
||||
.analysis-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-left: 12rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.analysis-content {
|
||||
.analysis-text {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
line-height: 1.8;
|
||||
word-break: break-word;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.back-btn {
|
||||
width: 300rpx;
|
||||
height: 80rpx;
|
||||
|
||||
@ -168,7 +168,7 @@
|
||||
<view class="bottom-button-container">
|
||||
<button class="evaluate-btn" @click="handleEvaluate">
|
||||
<u-icon name="file-text" size="18" color="#fff" style="margin-right: 8rpx;"></u-icon>
|
||||
<text>问卷评估</text>
|
||||
<text>AI数字问卷</text>
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@ -461,6 +461,33 @@ const convertHTMLToUrl = (html: string): string => {
|
||||
// 在 HTML 中添加脚本,自动向父窗口发送高度信息
|
||||
let processedHtml = html;
|
||||
|
||||
// 替换 CDN 地址为国内可用的 CDN
|
||||
processedHtml = processedHtml.replace(
|
||||
/https:\/\/cdn\.jsdelivr\.net\/npm\/chart\.js/g,
|
||||
'https://cdn.bootcdn.net/ajax/libs/Chart.js/3.9.1/chart.min.js'
|
||||
);
|
||||
|
||||
// 添加 CDN 加载失败的备用方案(使用字符编码避免 Vue 解析错误)
|
||||
const headEndTag = [60, 47, 104, 101, 97, 100, 62].map(c => String.fromCharCode(c)).join('');
|
||||
if (processedHtml.includes(headEndTag)) {
|
||||
// 构建脚本标签
|
||||
const scriptOpen = [60, 115, 99, 114, 105, 112, 116, 62].map(c => String.fromCharCode(c)).join('');
|
||||
const scriptClose = [60, 47, 115, 99, 114, 105, 112, 116, 62].map(c => String.fromCharCode(c)).join('');
|
||||
|
||||
// 第一段:错误标志
|
||||
const script1 = scriptOpen + 'window.chartLoadError=false;' + scriptClose;
|
||||
|
||||
// 第二段:加载主 CDN 并设置错误标志
|
||||
const script2 = '<script src="https://cdn.bootcdn.net/ajax/libs/Chart.js/3.9.1/chart.min.js" onerror="window.chartLoadError=true;"><' + '/script>';
|
||||
|
||||
// 第三段:备用加载逻辑
|
||||
const script3Content = 'setTimeout(function(){if(window.chartLoadError||typeof Chart==="undefined"){var s=document.createElement("script");s.src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js";s.onerror=function(){var s2=document.createElement("script");s2.src="https://unpkg.com/chart.js@3.9.1/dist/chart.min.js";document.head.appendChild(s2);};document.head.appendChild(s);}},2000);';
|
||||
const script3 = scriptOpen + script3Content + scriptClose;
|
||||
|
||||
const fallbackScript = script1 + script2 + script3;
|
||||
processedHtml = processedHtml.replace(headEndTag, fallbackScript + headEndTag);
|
||||
}
|
||||
|
||||
// 检查是否已经包含自动调整高度的脚本
|
||||
if (!processedHtml.includes('postMessage')) {
|
||||
// 构建脚本内容(使用字符编码避免 Vue 编译器解析)
|
||||
@ -468,7 +495,8 @@ const convertHTMLToUrl = (html: string): string => {
|
||||
const scriptClose = [60, 47, 115, 99, 114, 105, 112, 116, 62].map(c => String.fromCharCode(c)).join('');
|
||||
// 优化脚本:只在初始加载和图表渲染完成后发送一次高度,避免循环更新
|
||||
// 完全禁用 resize 事件监听,防止循环
|
||||
const scriptContent = '(function(){let hasSent=false;let sentHeight=0;function sendHeightOnce(){try{if(hasSent)return;const h=Math.max(document.body.scrollHeight||0,document.documentElement.scrollHeight||0);if(h>100&&h!==sentHeight&&window.parent&&window.parent!==window){sentHeight=h;hasSent=true;window.parent.postMessage({type:"iframe-height",height:h},"*");}}catch(e){}}function sendWithDelay(){setTimeout(sendHeightOnce,800);}if(document.readyState==="complete"){sendWithDelay();}else{window.addEventListener("load",sendWithDelay);}if(typeof Chart!=="undefined"){const o=Chart;Chart=function(...a){const c=new o(...a);sendWithDelay();return c;};}})();';
|
||||
// 延长等待时间到 1500ms,添加延迟检测 Chart 对象
|
||||
const scriptContent = '(function(){let hasSent=false;let sentHeight=0;function sendHeightOnce(){try{if(hasSent)return;const h=Math.max(document.body.scrollHeight||0,document.documentElement.scrollHeight||0);if(h>100&&h!==sentHeight&&window.parent&&window.parent!==window){sentHeight=h;hasSent=true;window.parent.postMessage({type:"iframe-height",height:h},"*");}}catch(e){}}function sendWithDelay(){setTimeout(sendHeightOnce,1500);}if(document.readyState==="complete"){sendWithDelay();}else{window.addEventListener("load",sendWithDelay);}if(typeof Chart!=="undefined"){const o=Chart;Chart=function(...a){const c=new o(...a);sendWithDelay();return c;};}else{setTimeout(function(){if(typeof Chart!=="undefined"){const o=Chart;Chart=function(...a){const c=new o(...a);sendWithDelay();return c;};}},3000);}})();';
|
||||
const autoResizeScript = scriptOpen + scriptContent + scriptClose;
|
||||
|
||||
// 构建 body 结束标签
|
||||
|
||||
@ -500,6 +500,33 @@ const convertHTMLToUrl = (html: string): string => {
|
||||
// 在 HTML 中添加脚本,自动向父窗口发送高度信息
|
||||
let processedHtml = html;
|
||||
|
||||
// 替换 CDN 地址为国内可用的 CDN
|
||||
processedHtml = processedHtml.replace(
|
||||
/https:\/\/cdn\.jsdelivr\.net\/npm\/chart\.js/g,
|
||||
'https://cdn.bootcdn.net/ajax/libs/Chart.js/3.9.1/chart.min.js'
|
||||
);
|
||||
|
||||
// 添加 CDN 加载失败的备用方案(使用字符编码避免 Vue 解析错误)
|
||||
const headEndTag = [60, 47, 104, 101, 97, 100, 62].map(c => String.fromCharCode(c)).join('');
|
||||
if (processedHtml.includes(headEndTag)) {
|
||||
// 构建脚本标签
|
||||
const scriptOpen = [60, 115, 99, 114, 105, 112, 116, 62].map(c => String.fromCharCode(c)).join('');
|
||||
const scriptClose = [60, 47, 115, 99, 114, 105, 112, 116, 62].map(c => String.fromCharCode(c)).join('');
|
||||
|
||||
// 第一段:错误标志
|
||||
const script1 = scriptOpen + 'window.chartLoadError=false;' + scriptClose;
|
||||
|
||||
// 第二段:加载主 CDN 并设置错误标志
|
||||
const script2 = '<script src="https://cdn.bootcdn.net/ajax/libs/Chart.js/3.9.1/chart.min.js" onerror="window.chartLoadError=true;"><' + '/script>';
|
||||
|
||||
// 第三段:备用加载逻辑
|
||||
const script3Content = 'setTimeout(function(){if(window.chartLoadError||typeof Chart==="undefined"){var s=document.createElement("script");s.src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js";s.onerror=function(){var s2=document.createElement("script");s2.src="https://unpkg.com/chart.js@3.9.1/dist/chart.min.js";document.head.appendChild(s2);};document.head.appendChild(s);}},2000);';
|
||||
const script3 = scriptOpen + script3Content + scriptClose;
|
||||
|
||||
const fallbackScript = script1 + script2 + script3;
|
||||
processedHtml = processedHtml.replace(headEndTag, fallbackScript + headEndTag);
|
||||
}
|
||||
|
||||
// 检查是否已经包含自动调整高度的脚本
|
||||
if (!processedHtml.includes('postMessage')) {
|
||||
// 构建脚本内容(使用字符编码避免 Vue 编译器解析)
|
||||
@ -507,7 +534,7 @@ const convertHTMLToUrl = (html: string): string => {
|
||||
const scriptClose = [60, 47, 115, 99, 114, 105, 112, 116, 62].map(c => String.fromCharCode(c)).join('');
|
||||
// 优化脚本:只在初始加载和图表渲染完成后发送一次高度,避免循环更新
|
||||
// 完全禁用 resize 事件监听,防止循环
|
||||
const scriptContent = '(function(){let hasSent=false;let sentHeight=0;function sendHeightOnce(){try{if(hasSent)return;const h=Math.max(document.body.scrollHeight||0,document.documentElement.scrollHeight||0);if(h>100&&h!==sentHeight&&window.parent&&window.parent!==window){sentHeight=h;hasSent=true;window.parent.postMessage({type:"iframe-height",height:h},"*");}}catch(e){}}function sendWithDelay(){setTimeout(sendHeightOnce,800);}if(document.readyState==="complete"){sendWithDelay();}else{window.addEventListener("load",sendWithDelay);}if(typeof Chart!=="undefined"){const o=Chart;Chart=function(...a){const c=new o(...a);sendWithDelay();return c;};}})();';
|
||||
const scriptContent = '(function(){let hasSent=false;let sentHeight=0;function sendHeightOnce(){try{if(hasSent)return;const h=Math.max(document.body.scrollHeight||0,document.documentElement.scrollHeight||0);if(h>100&&h!==sentHeight&&window.parent&&window.parent!==window){sentHeight=h;hasSent=true;window.parent.postMessage({type:"iframe-height",height:h},"*");}}catch(e){}}function sendWithDelay(){setTimeout(sendHeightOnce,1500);}if(document.readyState==="complete"){sendWithDelay();}else{window.addEventListener("load",sendWithDelay);}if(typeof Chart!=="undefined"){const o=Chart;Chart=function(...a){const c=new o(...a);sendWithDelay();return c;};}else{setTimeout(function(){if(typeof Chart!=="undefined"){const o=Chart;Chart=function(...a){const c=new o(...a);sendWithDelay();return c;};}},3000);}})();';
|
||||
const autoResizeScript = scriptOpen + scriptContent + scriptClose;
|
||||
|
||||
// 构建 body 结束标签
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user