Files
lucky_shop/pages_tool/form/formdata.vue
ZF sun 51274b70ce feat(form): add url params透传和member_id上报功能
1. 为form和formdata页面新增通用URL参数透传逻辑,过滤保留字段后收集参数
2. 处理scene参数中的额外透传参数
3. 提交请求时携带url_params和当前会员ID
4. 修复代码格式问题
2026-07-31 08:48:23 +08:00

233 lines
6.4 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="system-form-wrap">
<!-- 复用 diy-form:banner / tip / 表单字段 / 提交按钮 全部由其内部渲染,样式(bannerPaddingX/tipColor/submitBgColor 等)由 form_config 控制。
@submit 接管提交逻辑(带 uniacid + showModal) -->
<diy-form
ref="form"
:value="diyValue"
dataMode="raw"
@submit="create"
/>
</view>
</view>
</block>
<block v-else>
<ns-empty :text="complete ? $lang('form.formdata.submitSuccess') : $lang('form.formdata.noFormInfo')" :isIndex="false"></ns-empty>
</block>
<loading-cover ref="loadingCover"></loading-cover>
<ns-login ref="login"></ns-login>
<to-top v-if="showTop" @toTop="scrollToTopNative()"></to-top>
</view>
</template>
<script>
import diyForm from '@/components-diy/diy-form.vue';
import scroll from '@/common/js/scroll-view.js';
export default {
components: {
diyForm
},
mixins: [scroll],
data() {
return {
id: 0,
detail: null,
isRepeat: false,
complete: false,
scroll: true,
uniacid: 0,
isFromMpWebView: false, // 是否是从微信小程序的WebView跳转过来的
hideNavbar: false, // 查询参数中支持隐藏Navbar
urlParams: {}, // 通用 URL 透传参数收集
// #ifdef H5
formTitle: '', // 查询参数传入的Title
enableSetTitle: false, // 查询参数传入的是否可以强制设置Title
// #endif
}
},
computed: {
// 构造 diy-form raw 模式期望的 value 形态:
// - jsonData:透传给 ns-newform(已是 ns-newform 期望的 [{ controller, value, val }])
// - formConfig:后端返回 camelCase(如 formPaddingX / formBgColor / labelFontSize),
// diy-form 内部 mergedFormConfig 同时兼容 snake_case 后再交给 ns-newform
// - show_banner / form_banner:交给 diy-form 渲染 banner,样式走 form_config.bannerPaddingX;form_banner 给保底图
// - show_tip / form_tip:交给 diy-form 渲染 tip,样式走 form_config;form_tip 给保底文案
// 注:本 computed 只在 <block v-if="detail"> 内被消费,无需 null 守卫
diyValue() {
return {
jsonData: this.detail.json_data,
formConfig: this.detail.form_config,
show_banner: this.detail.show_banner,
form_banner: this.detail.form_banner || 'public/uniapp/form/banner.png',
show_tip: this.detail.show_tip,
form_tip: this.detail.form_tip || this.$lang('form.formdata.formTipPlaceholder')
}
}
},
onLoad(options) {
if (!options.uniacid) {
uni.showModal({
title: this.$lang('form.formdata.tip'),
content: this.$lang('form.formdata.paramError'),
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';
this.hideNavbar = Boolean(options?.hide_navbar);
// 通用 URL 参数收集:除业务保留字段外,其余全部透传给后端
// 后端会做卫生过滤并广播事件,供 recommend 等插件消费
const reservedKeys = ['uniacid', 'id', 'scene', 'from', 'hide_navbar', 'title', 'enable_set_title'];
this.urlParams = {};
for (let key in options) {
if (reservedKeys.indexOf(key) !== -1) continue;
this.urlParams[key] = options[key];
}
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]
}
// scene 中也可能携带其他参数
let pair = item.split('=');
if (pair.length === 2 && pair[0] !== 'id') {
this.urlParams[pair[0]] = pair[1];
}
})
}
// #ifdef H5
if (this.isFromMpWebView || this.hideNavbar) {
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
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 });
},
// 由 diy-form 内置提交按钮触发:diy-form 已先做 verify(),仅在通过时才 emit('submit', formData)
create(formData) {
if (this.isRepeat) return
this.isRepeat = true
this.$api.sendRequest({
url: '/form/api/form/create',
data: {
form_id: this.id,
form_data: typeof formData === 'string' ? formData : JSON.stringify(formData),
uniacid: this.uniacid,
url_params: JSON.stringify(this.urlParams),
member_id: this.memberInfo ? this.memberInfo.id : 0
},
success: res => {
if (res.code == 0) {
uni.showModal({
title: this.$lang('form.formdata.tip'),
content: this.$lang('form.formdata.submitSuccess'),
showCancel: false,
success: () => { }
})
} else {
this.isRepeat = false
this.$util.showToast({
title: res.message
})
}
}
})
}
}
}
</script>
<style lang="scss" scoped>
page {
background: #fff;
}
.system-form-wrap {
overflow: hidden;
margin: 0 0 60rpx 0;
}
// 穿透 diy-form 包装层:消除其自带的 10rpx 圆角与白色背景,
// 让 form 内容区域保持与原始 ns-newform 接入时一致的视觉
.system-form-wrap ::v-deep .diy-from {
background: transparent;
border-radius: 0;
}
::v-deep .mescroll-totop {
/* #ifdef H5 */
right: 27rpx !important;
bottom: 120rpx !important;
/* #endif */
/* #ifdef MP */
right: 27rpx !important;
bottom: 180rpx !important;
/* #endif */
}
</style>