hookehuyr

✨ feat(测试表单渲染结构和保存表单数据):

......@@ -14,7 +14,7 @@ VITE_ID = 13761653761
VITE_PIN =
# 反向代理服务器地址
# VITE_PROXY_TARGET = http://oa-dev.onwall.cn
VITE_PROXY_TARGET = http://oa-dev.onwall.cn
# VITE_PROXY_TARGET = http://guanzong.onwall.cn
# PC端地址
......
......@@ -11,7 +11,7 @@ VITE_APP_ID =
VITE_APP_PIN =
# 反向代理服务器地址
# VITE_PROXY_TARGET = http://guanzong.onwall.cn
VITE_PROXY_TARGET = http://oa.onwall.cn
# PC端地址
# VITE_MOBILE_URL = http://oa.onwall.cn/f/guanzong/web/
......
......@@ -2,7 +2,7 @@
* @Author: hookehuyr hookehuyr@gmail.com
* @Date: 2022-05-26 23:52:36
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-09-06 16:24:19
* @LastEditTime: 2022-11-17 13:34:07
* @FilePath: /data-table/src/App.vue
* @Description:
-->
......@@ -16,37 +16,39 @@
</template>
<script setup>
import { mainStore, useTitle } from '@/utils/generatePackage'
import { computed, watchEffect, onMounted } from 'vue';
import { useRoute, useRouter } from 'vue-router'
import { Toast } from 'vant';
import { mainStore, useTitle } from "@/utils/generatePackage";
import { computed, watchEffect, onMounted } from "vue";
import { useRoute, useRouter } from "vue-router";
import { Toast } from "vant";
// 会根据配置判断是否显示调试控件
// eslint-disable-next-line no-unused-vars
import vConsole from '@/utils/vconsole'
import vConsole from "@/utils/vconsole";
// 初始化WX环境
// import wx from 'weixin-js-sdk'
// import { wxJsAPI } from '@/api/wx/config'
// import { apiList } from '@/api/wx/jsApiList.js'
import { wxInfo } from '@/utils/tools'
import { wxInfo } from "@/utils/tools";
// 使用 include + pinia 状态管理动态缓存页面
const store = mainStore()
const keepPages = computed(() => store.getKeepPages)
const store = mainStore();
const keepPages = computed(() => store.getKeepPages);
// // TAG: 全局设置页面标题
// const $route = useRoute();
watchEffect(
() => useTitle('表单标题')
)
watchEffect(() => useTitle("表单标题"));
// 监听路由变化
// 切换路由页面返回顶部
const $router = useRouter();
watch(() => $router.currentRoute.value, (newValue, oldValue) => {
watch(
() => $router.currentRoute.value,
(newValue, oldValue) => {
nextTick(() => {
// document.getElementById('app')?.scrollIntoView();
})
});
// console.warn(wxInfo().isMobile);
}, { immediate: true })
},
{ immediate: true }
);
// TAG: 全局配置Toast
// Toast.setDefaultOptions({
......@@ -55,7 +57,7 @@ watch(() => $router.currentRoute.value, (newValue, oldValue) => {
// });
// web端判断
const is_pc = computed(() => wxInfo().isPC)
const is_pc = computed(() => wxInfo().isPC);
onMounted(async () => {
// const { data } = await wxJsAPI();
......@@ -67,18 +69,20 @@ onMounted(async () => {
// wx.error((err) => {
// console.warn(err);
// });
})
});
</script>
<style lang="less">
@prefix: ~'@{namespace}-x';
@prefix: ~"@{namespace}-x";
html,
body {
width: 100%;
height: 100%;
color: @base-font-color;
background-color: #F7F8FA;
background-color: #f7f8fa;
padding: 0;
margin: 0;
}
body {
......
/*
* @Date: 2022-06-17 14:54:29
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-11-17 13:49:35
* @FilePath: /data-table/src/api/data.js
* @Description: 表单数据接口
*/
import { fn, fetch } from '@/api/fn';
const Api = {
ADD_FORM_DATA: '/srv/?a=add_formdata',
}
/**
* @description: 添加表单数据
* @param: form_code 表单唯一标识
* @param: data 待添加的数据,json对象结构;键值对记录变更的字段和值;
*/
export const addFormDataAPI = (params) => fn(fetch.post(Api.ADD_FORM_DATA, params));
/*
* @Date: 2022-06-17 14:54:29
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-11-17 10:41:39
* @FilePath: /data-table/src/api/form.js
* @Description: 表单接口
*/
import { fn, fetch } from '@/api/fn';
const Api = {
FORM_QUERY: '/srv/?a=query_form',
}
/**
* @description: 查询表单
* @param: client_id 主体客户id
* @param: form_code 表单唯一标识
* @param: name 表单名称,模糊查询
*/
export const queryFormAPI = (params) => fn(fetch.get(Api.FORM_QUERY, params));
/*
* @Date: 2022-06-17 14:54:29
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-08-29 13:58:16
* @LastEditTime: 2022-11-17 13:46:01
* @FilePath: /data-table/src/api/index.js
* @Description: 首页接口
*/
......@@ -9,7 +9,7 @@ import { fn, fetch } from '@/api/fn';
const Api = {
INDEX: '/srv/?a=home_page',
}
/**
* @description: 首页接口
* @returns HOMEBANNER 轮播区
......
......@@ -2,7 +2,7 @@
* @Author: hookehuyr hookehuyr@gmail.com
* @Date: 2022-05-28 10:17:40
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-09-06 18:01:36
* @LastEditTime: 2022-11-17 10:17:01
* @FilePath: /data-table/src/utils/axios.js
* @Description:
*/
......@@ -13,7 +13,7 @@ import { strExist } from '@/utils/tools'
// import { parseQueryString } from '@/utils/tools'
axios.defaults.params = {
f: 'customize',
f: 'custom_form',
};
/**
......
<!--
* @Date: 2022-07-18 10:22:22
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-09-16 17:32:55
* @LastEditTime: 2022-11-17 14:08:01
* @FilePath: /data-table/src/views/index.vue
* @Description: 首页
-->
......@@ -11,302 +11,355 @@
<div class="table-box">
<van-form @submit="onSubmit">
<van-cell-group>
<component :ref="item.component_props.name" v-for="(item, index) in mockData" :key="index" :is="item.component" :item="item" @active="onActive" />
<component
:ref="item.component_props.name"
v-for="(item, index) in formData"
:key="index"
:is="item.component"
:item="item"
@active="onActive"
/>
</van-cell-group>
<div style="margin: 16px;">
<van-button round block type="primary" native-type="submit">
提交
</van-button>
<div style="margin: 16px">
<van-button round block type="primary" native-type="submit"> 提交 </van-button>
</div>
</van-form>
</div>
</template>
<script setup>
import { createComponentType } from '@/hooks/useComponentType'
import _ from 'lodash'
import { createComponentType } from "@/hooks/useComponentType";
import _ from "lodash";
import { useRoute } from "vue-router";
import { queryFormAPI } from "@/api/form.js";
import { addFormDataAPI } from "@/api/data.js";
const table_cover = ref('');
const table_title = ref('');
const $route = useRoute();
const table_cover = ref("");
const table_title = ref("");
const mockData = ref([]);
const postData = ref({})
const formData = ref([]);
const postData = ref({});
onMounted(() => {
table_cover.value = 'https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg'
table_title.value = '这是一个表单的描述'
mockData.value = [
// 格式化表单数据结构
const formatData = (data) => {
const arr = [];
data.forEach((field) => {
// 解析组件属性
const component_props = {
name: field.component_code,
};
field.property_list.forEach((prop) => {
const key = prop["property_code"];
const obj = {
[key]:
prop["setting_value"].length > 1
? prop["setting_value"]
: prop["setting_value"][0],
};
Object.assign(component_props, obj);
});
arr.push({
key: field.field_name,
value: "",
component: "",
component_props,
});
});
return arr;
};
onMounted(async () => {
const { data } = await queryFormAPI({ form_code: $route.query.code });
const form_data = data[0];
table_cover.value = "https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg";
table_title.value = form_data.description;
formData.value = formatData(form_data.field_list);
// mockData.value = [
// {
// key: 'phone',
// value: '',
// component: '',
// key: "phone",
// value: "",
// component: "",
// component_props: {
// name: 'phone',
// label: '手机号',
// placeholder: '请输入手机号',
// name: "phone",
// label: "手机号",
// placeholder: "请输入手机号",
// required: true,
// },
// },
// {
// key: 'username',
// value: 'test',
// component: '',
// key: "field_1",
// value: "test",
// component: "",
// component_props: {
// name: 'text',
// label: '用户名',
// placeholder: '请输入用户名',
// name: "text",
// label: "用户名",
// placeholder: "请输入用户名",
// required: true,
// readonly: true,
// disabled: true,
// align: 'left',
// },
// },
// {
// key: 'email',
// value: '',
// component: '',
// component_props: {
// name: 'email',
// label: '邮箱',
// placeholder: '请输入邮箱',
// required: true,
// },
// },
// {
// key: 'id_code',
// value: '',
// component: '',
// component_props: {
// name: 'id_code',
// label: '身份证号码',
// placeholder: '请输入身份证号码',
// required: true,
// },
// },
// {
// key: 'age',
// value: '',
// component: '',
// component_props: {
// label: '年龄',
// placeholder: '请输入年龄',
// name: 'number',
// required: true,
// },
// },
{
key: 'gender',
value: '',
component: '',
component_props: {
name: 'radio',
label: '性别',
placeholder: '',
direction: 'horizontal',
options: [{
key: '男',
value: '男'
}, {
key: '女',
value: '女'
}],
required: true,
},
},
// {
// key: 'hobby',
// value: [],
// label: '兴趣爱好',
// component: '',
// component_props: {
// name: 'checkbox',
// direction: 'horizontal',
// max: '3'
// },
// options: [{
// key: '足球',
// value: '足球'
// }, {
// key: '篮球',
// value: '篮球'
// }, {
// key: '羽毛球',
// value: '羽毛球'
// }, {
// key: '乒乓球',
// value: '乒乓球'
// }]
// },
// {
// key: 'message',
// value: '一种可以用来记录,展示文字信息的载体,有比较强的时效性。一般以黑板、木板为载体。用来留言。各种各样的留言使用。留言板还有引申的“网络留言板”。这个和网络留言本不一样的地方是留言板一般比较集中的反应信息的。',
// label: '留言',
// placeholder: '请输入留言',
// component: '',
// component_props: {
// name: 'textarea',
// rows: 3,
// maxlength: null,
// },
// },
// {
// key: 'vehicle',
// value: '自行车',
// label: '交通工具',
// placeholder: '请选择交通工具',
// component: '',
// component_props: {
// name: 'picker'
// align: "left",
// },
// options: [
// { text: '自行车', value: '自行车' },
// { text: '汽车', value: '汽车' },
// { text: '地铁', value: '地铁' },
// ],
// required: true,
// },
// {
// key: 'sign',
// value: '',
// label: '电子签名',
// placeholder: '',
// component: '',
// component_props: {
// name: 'sign',
// },
// required: true,
// },
// {
// key: 'city',
// value: '天津市/天津市/和平区',
// city_code: '120101',
// label: '地址',
// address: '',
// placeholder: '请选择省市区',
// component_props: {
// name: 'area_picker'
// },
// },
// {
// key: 'date',
// value: '2022-10',
// label: '日期选择',
// placeholder: '请选择日期',
// component_props: {
// name: 'date_picker',
// title: '请选择',
// min_date: new Date(),
// columns_type: ['year', 'month']
// },
// },
// {
// key: 'time',
// value: '',
// label: '时间选择',
// placeholder: '请选择时间',
// component_props: {
// name: 'time_picker',
// title: '请选择',
// columns_type: ['hour', 'minute']
// },
// required: true,
// },
// {
// key: 'image_src',
// value: '',
// label: '图片上传',
// component_props: {
// name: 'image_uploader',
// image_type: ['jpg', 'png'],
// multiple: false
// }
// }
// {
// key: 'datetime',
// value: '2022-06-01 12:00',
// component_props: {
// name: 'datetime_picker',
// title: '请选择',
// label: '日期时间',
// placeholder: '请选择日期时间',
// minDate: new Date(),
// required: true,
// },
// },
// {
// key: 'date',
// value: '',
// label: '日历选择',
// placeholder: '请选择日历日期',
// component: '',
// component_props: {
// name: 'calendar',
// type: 'range', // 日期区间 ['multiple', 'range']
// minDate: new Date(2022, 0, 1), // 最小日期
// maxDate: new Date(2023, 0, 31), // 最大日期
// maxRange: 5, // 最大可选天数
// },
// required: false,
// },
// {
// key: 'rate',
// value: '',
// label: '评分',
// placeholder: '请选择评分',
// component_props: {
// name: 'rate_picker',
// count: 10
// },
// required: true,
// }
];
// // {
// // key: 'email',
// // value: '',
// // component: '',
// // component_props: {
// // name: 'email',
// // label: '邮箱',
// // placeholder: '请输入邮箱',
// // required: true,
// // },
// // },
// // {
// // key: 'id_code',
// // value: '',
// // component: '',
// // component_props: {
// // name: 'id_code',
// // label: '身份证号码',
// // placeholder: '请输入身份证号码',
// // required: true,
// // },
// // },
// // {
// // key: 'age',
// // value: '',
// // component: '',
// // component_props: {
// // label: '年龄',
// // placeholder: '请输入年龄',
// // name: 'number',
// // required: true,
// // },
// // },
// // {
// // key: 'gender',
// // value: '',
// // component: '',
// // component_props: {
// // name: 'radio',
// // label: '性别',
// // placeholder: '',
// // direction: 'horizontal',
// // options: [{
// // key: '男',
// // value: '男'
// // }, {
// // key: '女',
// // value: '女'
// // }],
// // required: true,
// // },
// // },
// // {
// // key: 'hobby',
// // value: [],
// // component: '',
// // component_props: {
// // name: 'checkbox',
// // label: '兴趣爱好',
// // placeholder: '',
// // direction: 'horizontal',
// // max: '3',
// // options: [{
// // key: '足球',
// // value: '足球'
// // }, {
// // key: '篮球',
// // value: '篮球'
// // }, {
// // key: '羽毛球',
// // value: '羽毛球'
// // }, {
// // key: '乒乓球',
// // value: '乒乓球'
// // }],
// // },
// // },
// // {
// // key: 'message',
// // value: '一种可以用来记录,展示文字信息的载体,有比较强的时效性。一般以黑板、木板为载体。用来留言。各种各样的留言使用。留言板还有引申的“网络留言板”。这个和网络留言本不一样的地方是留言板一般比较集中的反应信息的。',
// // label: '留言',
// // placeholder: '请输入留言',
// // component: '',
// // component_props: {
// // name: 'textarea',
// // rows: 3,
// // maxlength: null,
// // },
// // },
// // {
// // key: 'vehicle',
// // value: '自行车',
// // label: '交通工具',
// // placeholder: '请选择交通工具',
// // component: '',
// // component_props: {
// // name: 'picker'
// // },
// // options: [
// // { text: '自行车', value: '自行车' },
// // { text: '汽车', value: '汽车' },
// // { text: '地铁', value: '地铁' },
// // ],
// // required: true,
// // },
// // {
// // key: 'sign',
// // value: '',
// // label: '电子签名',
// // placeholder: '',
// // component: '',
// // component_props: {
// // name: 'sign',
// // },
// // required: true,
// // },
// // {
// // key: 'city',
// // value: '天津市/天津市/和平区',
// // city_code: '120101',
// // label: '地址',
// // address: '',
// // placeholder: '请选择省市区',
// // component_props: {
// // name: 'area_picker'
// // },
// // },
// // {
// // key: 'date',
// // value: '2022-10',
// // label: '日期选择',
// // placeholder: '请选择日期',
// // component_props: {
// // name: 'date_picker',
// // title: '请选择',
// // min_date: new Date(),
// // columns_type: ['year', 'month']
// // },
// // },
// // {
// // key: 'time',
// // value: '',
// // label: '时间选择',
// // placeholder: '请选择时间',
// // component_props: {
// // name: 'time_picker',
// // title: '请选择',
// // columns_type: ['hour', 'minute']
// // },
// // required: true,
// // },
// // {
// // key: 'image_src',
// // value: '',
// // label: '图片上传',
// // component_props: {
// // name: 'image_uploader',
// // image_type: ['jpg', 'png'],
// // multiple: false
// // }
// // }
// // {
// // key: 'datetime',
// // value: '2022-06-01 12:00',
// // component_props: {
// // name: 'datetime_picker',
// // title: '请选择',
// // label: '日期时间',
// // placeholder: '请选择日期时间',
// // minDate: new Date(),
// // required: true,
// // },
// // },
// // {
// // key: 'date',
// // value: '',
// // label: '日历选择',
// // placeholder: '请选择日历日期',
// // component: '',
// // component_props: {
// // name: 'calendar',
// // type: 'range', // 日期区间 ['multiple', 'range']
// // minDate: new Date(2022, 0, 1), // 最小日期
// // maxDate: new Date(2023, 0, 31), // 最大日期
// // maxRange: 5, // 最大可选天数
// // },
// // required: false,
// // },
// // {
// // key: 'rate',
// // value: '',
// // label: '评分',
// // placeholder: '请选择评分',
// // component_props: {
// // name: 'rate_picker',
// // count: 10
// // },
// // required: true,
// // }
// ];
// 生成自定义组件
createComponentType(mockData.value)
})
createComponentType(formData.value);
});
const sign = ref(null);
const rate_picker = ref(null);
const onSubmit = (values) => {
const onSubmit = async (values) => {
// 合并自定义字段到提交表单字段
postData.value = _.assign(postData.value, values);
// console.warn(mockData.value);
// 检查非表单输入项
if (validOther()) { // 通过验证
console.warn(postData.value);
console.warn('通过验证');
if (validOther()) {
// 通过验证
const result = await addFormDataAPI({
form_code: $route.query.code,
data: JSON.stringify(postData.value),
});
console.warn(result);
// if (code) {
// console.warn("提交成功");
// console.warn(data);
// }
// console.warn("通过验证");
} else {
console.warn('不通过验证');
console.warn("不通过验证");
}
};
const onActive = (item) => {
// 返回自定义字段
if (item.key === 'sign') {
postData.value['sign'] = item.value
if (item.key === "sign") {
postData.value["sign"] = item.value;
}
if (item.key === 'rate') {
postData.value['rate'] = item.value
if (item.key === "rate") {
postData.value["rate"] = item.value;
}
}
};
const validOther = () => {
// 检验没有绑定name的输入项
let flag = true;
if (sign.value) { // 检验电子签名
if (sign.value) {
// 检验电子签名
flag = sign.value[0].validSign();
}
if (rate_picker.value) { // 检验评分
if (rate_picker.value) {
// 检验评分
flag = rate_picker.value[0].validRate();
}
return flag;
}
};
</script>
<style lang="less" scoped>
.table-title {
.table-title {
padding: 1rem;
}
.table-box {
}
.table-box {
padding: 1rem;
}
}
</style>
......
......@@ -62,6 +62,7 @@ export default ({ command, mode }) => {
"@css": path.resolve(__dirname, "src/assets/css"),
"@mock": path.resolve(__dirname, "src/assets/mock"),
"common": path.resolve(__dirname, "src/common"),
"@api": path.resolve(__dirname, "src/api"),
},
// dedupe: [''], // 如果你在你的应用程序中有相同依赖的副本(比如 monorepos),使用这个选项来强制 Vite 总是将列出的依赖关系解析到相同的副本(从项目根目录)。
// conditions: [''], // 在解析包的 情景导出 时允许的附加条件。
......