Files
lucky_shop/pages_tool/form/formdata.vue
ZF sun fe9cbcd21d refactor(form, diy-form): 重构表单组件复用逻辑,新增raw模式适配现有表单数据
1. 新增diy-form组件的raw数据源模式,支持直接透传ns-newform格式的表单数据
2. 新增showSubmit配置项,支持隐藏内置提交按钮由父页面自行实现提交逻辑
3. 暴露verify和getFormData方法供父组件调用
4. 替换pages_tool/form/formdata.vue的旧表单组件为diy-form,适配新的调用方式
5. 新增样式穿透修复diy-form默认样式与原有页面风格不一致的问题
2026-06-12 11:09:08 +08:00

254 lines
5.9 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view :style="themeColor">
<block v-if="detail">
<view class="page">
<view class="form-banner" v-if="detail.show_banner > 0">
<image :src="$util.img(formBanner)" mode="widthFix"></image>
</view>
<view class="form-tip">
<view class="system-form-tip" v-if="detail.show_tip > 0">{{ formTip }}</view>
</view>
<view class="system-form-wrap">
<!-- 复用 diy-form 渲染表单字段:raw 模式直接透传 detail.json_data,隐藏内置 banner/tip/提交按钮(页面自己渲染) -->
<diy-form
ref="form"
:value="diyValue"
dataMode="raw"
:showSubmit="false"
/>
<button class="button mini" style="font-size:32rpx;" type="primary" size="mini"
@click="create">提交</button>
</view>
</view>
</block>
<block v-else>
<ns-empty :text="complete ? '提交成功' : '未获取到表单信息'" :isIndex="false"></ns-empty>
</block>
<loading-cover ref="loadingCover"></loading-cover>
<ns-login ref="login"></ns-login>
</view>
</template>
<script>
import diyForm from '@/components-diy/diy-form.vue';
export default {
components: {
diyForm
},
data() {
return {
id: 0,
detail: null,
isRepeat: false,
complete: false,
scroll: true,
uniacid: 0,
isFromMpWebView: false, // 是否是从微信小程序的WebView跳转过来的
// #ifdef H5
formTitle: '', // 查询参数传入的Title
enableSetTitle: false, // 查询参数传入的是否可以强制设置Title
// #endif
}
},
computed: {
formBanner() {
const bannerImg = this.detail?.form_banner
return bannerImg ? bannerImg : 'public/uniapp/form/banner.png'
},
formTip() {
const tip = this.detail?.form_tip
console.log('formTip computed, tip value:', tip, 'truthy:', !!tip)
return tip ? tip : '请填写表单所需信息'
},
// 构造 diy-form raw 模式期望的 value 形态:
// - jsonData:透传给 ns-newform(已是 ns-newform 期望的 [{ controller, value, val }])
// - formConfig:snake_case 表单配置,diy-form 内部 mergedFormConfig 会做 camelCase 转换
// - 不传 show_banner / show_tip:让 diy-form 自带的 banner/tip 不渲染(页面已自渲染)
// 注:本 computed 只在 <block v-if="detail"> 内被消费,无需 null 守卫
diyValue() {
return {
jsonData: this.detail.json_data,
formConfig: this.detail.form_config
}
}
},
onLoad(options) {
if (!options.uniacid) {
uni.showModal({
title: '提示',
content: '参数错误',
showCancel: false,
success: () => { }
})
return false
}
uni.setStorageSync('skipPrivacyCheck', true);
// #ifdef H5
this.formTitle = options?.title ?? '';
this.enableSetTitle = options?.enable_set_title == 1;
// #endif
this.uniacid = options.uniacid
this.id = options.id || 0
this.isFromMpWebView = options.from === 'mp-webview';
if (options.scene) {
const scene = decodeURIComponent(options.scene)
const params = scene.split('&')
params.length && params.forEach(item => {
if (item.indexOf('id') != -1) {
this.id = item.split('-')[1]
}
})
}
// #ifdef H5
if (this.isFromMpWebView) {
this.$nextTick(() => {
const navbar = document.querySelector('uni-page-head')
if (navbar) navbar.style.display = 'none'
})
}
// #endif
this.getData()
},
watch: {
storeToken(newVal, oldVal) {
newVal && this.getData()
}
},
onShow() {
this.updateNavbarTitle();
},
methods: {
getData() {
this.$api.sendRequest({
url: '/form/api/form/info',
data: {
form_id: this.id,
uniacid: this.uniacid
},
success: res => {
if (res.code == 0 && res.data) {
this.detail = res.data
console.log(`form data =>`, this.detail)
this.updateNavbarTitle();
}
this.$refs.loadingCover && this.$refs.loadingCover.hide()
},
fail: () => {
this.$refs.loadingCover && this.$refs.loadingCover.hide()
}
})
},
updateNavbarTitle() {
if (!this.detail?.form_name) return;
let formName = this.detail.form_name;
// #ifdef H5
if (this.enableSetTitle && this.formTitle) {
formName = this.formTitle;
}
// #endif
uni.setNavigationBarTitle({ title: formName });
},
create() {
// 校验(ns-newform 校验失败时会内部 toast;返回 false 表示失败)
if (!this.$refs.form.verify()) return
if (this.isRepeat) return
this.isRepeat = true
this.$api.sendRequest({
url: '/form/api/form/create',
data: {
form_id: this.id,
form_data: JSON.stringify(this.$refs.form.getFormData()),
uniacid: this.uniacid
},
success: res => {
if (res.code == 0) {
uni.showModal({
title: '提示',
content: '提交成功',
showCancel: false,
success: () => { }
})
} else {
this.isRepeat = false
this.$util.showToast({
title: res.message
})
}
}
})
}
}
}
</script>
<style lang="scss" scoped>
page {
background: #fff;
}
.form-banner {
width: 100vw;
line-height: 1;
}
.form-banner image {
width: 100%;
line-height: 1;
}
.form-tip {
text-align: center;
}
.system-form-tip {
line-height: 120rpx;
font-weight: 600;
font-size: 30rpx;
}
.system-form-wrap {
border-radius: 32rpx;
overflow: hidden;
margin: 0 0 60rpx 0;
padding: 0 12rpx;
padding-top: 40rpx;
transform: translateY(-40rpx);
}
.system-form-wrap .button {
height: 80rpx;
line-height: 80rpx !important;
margin-top: 30rpx !important;
width: 84%;
margin-left: 28rpx !important;
border-radius: 80rpx;
background: #f4391c;
color: #fff;
}
.system-form-wrap .form-wrap {
background: #fff;
padding: 30rpx;
border-radius: 32rpx;
}
// 穿透 diy-form 包装层:消除其自带的 10rpx 圆角与白色背景,
// 让 form 内容区域保持与原始 ns-newform 接入时一致的视觉
.system-form-wrap ::v-deep .diy-from {
background: transparent;
border-radius: 0;
}
</style>