hookehuyr

数据结构适配调整

......@@ -7,39 +7,58 @@
-->
<template>
<div class="calendar-page">
<div class="label">{{ item.label }}<span v-if="item.required">&nbsp;*</span></div>
<van-field v-model="item.value" is-link readonly :name="item.key" :required="item.required"
:placeholder="item.placeholder" :rules="item.rules" @click="show = true" />
<van-calendar v-model:show="show"
:type="item.component_props.type" :max-range="item.component_props.maxRange"
:min-date="item.component_props.minDate" :max-date="item.component_props.maxDate"
<div class="label">
{{ item.component_props.label
}}<span v-if="item.component_props.required">&nbsp;*</span>
</div>
<van-field
v-model="item.value"
is-link
readonly
:name="item.key"
:required="item.component_props.required"
:placeholder="item.component_props.placeholder"
:rules="item.rules"
@click="show = true"
/>
<van-calendar
v-model:show="show"
:type="item.component_props.type"
:max-range="item.component_props.max_range"
:min-date="item.component_props.min_date"
:max-date="item.component_props.max_date"
:formatter="formatter"
first-day-of-week="1"
@month-show="onMonthShow"
@confirm="onConfirm" allow-same-day />
@confirm="onConfirm"
allow-same-day
/>
</div>
</template>
<script setup>
const props = defineProps({
item: Object
})
item: Object,
});
const show = ref(false);
const formatDate = (date) => `${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()}`;
const formatDate = (date) =>
`${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()}`;
const onConfirm = (value) => {
console.warn(props.item.component_props.type);
show.value = false;
if (props.item.component_props.type === 'range') { // 日期区间
if (props.item.component_props.type === "range") {
// 日期区间
const [start, end] = value;
props.item.value = `${formatDate(start)} ~ ${formatDate(end)}`;
} else if (props.item.component_props.type === 'multiple') { // 多个日期
const arr = []
value.forEach(element => {
arr.push(formatDate(element))
} else if (props.item.component_props.type === "multiple") {
// 多个日期
const arr = [];
value.forEach((element) => {
arr.push(formatDate(element));
});
props.item.value = arr.join(',');
props.item.value = arr.join(",");
} else {
props.item.value = formatDate(value);
}
......@@ -53,25 +72,25 @@ const formatter = (day) => {
if (month === 5) {
if (date === 1) {
day.topInfo = '劳动节';
day.topInfo = "劳动节";
} else if (date === 4) {
day.topInfo = '青年节';
day.topInfo = "青年节";
} else if (date === 11) {
day.text = '今天';
day.text = "今天";
}
}
if (month === 10) {
if (date === 1) {
day.topInfo = '国庆节';
day.type = 'disabled'
day.topInfo = "国庆节";
day.type = "disabled";
}
}
if (day.type === 'start') {
day.bottomInfo = '开始';
} else if (day.type === 'end') {
day.bottomInfo = '结束';
if (day.type === "start") {
day.bottomInfo = "开始";
} else if (day.type === "end") {
day.bottomInfo = "结束";
}
return day;
......@@ -80,10 +99,9 @@ const formatter = (day) => {
const onMonthShow = ({ date, title }) => {
// console.warn(date);
// console.warn(title);
if (title === '2022年12月') {
if (title === "2022年12月") {
}
}
};
</script>
<style lang="less" scoped>
......
......@@ -7,35 +7,52 @@
-->
<template>
<div class="date-picker-field">
<div class="label">{{ item.label }}<span v-if="item.required">&nbsp;*</span></div>
<van-field v-model="item.value" is-link readonly :name="item.key" :required="item.required"
:placeholder="item.placeholder" :rules="item.rules" @click="showPicker = true" />
<div class="label">
{{ item.component_props.label
}}<span v-if="item.component_props.required">&nbsp;*</span>
</div>
<van-field
v-model="item.value"
is-link
readonly
:name="item.key"
:required="item.component_props.required"
:placeholder="item.component_props.placeholder"
:rules="item.rules"
@click="showPicker = true"
/>
<van-popup v-model:show="showPicker" position="bottom">
<van-date-picker v-model="currentDate" :title="item.component_props.title"
:min-date="item.component_props.min_date" :max-date="item.component_props.max_date"
:columns-type="item.component_props.columns_type" @confirm="onConfirm" @cancel="showPicker = false" />
<van-date-picker
v-model="currentDate"
:title="item.component_props.title"
:min-date="item.component_props.min_date"
:max-date="item.component_props.max_date"
:columns-type="item.component_props.columns_type"
@confirm="onConfirm"
@cancel="showPicker = false"
/>
</van-popup>
</div>
</template>
<script setup>
import dayjs from 'dayjs';
import dayjs from "dayjs";
const props = defineProps({
item: Object
})
item: Object,
});
const showPicker = ref(false);
const currentDate = ref([]);
const onConfirm = ({ selectedValues, selectedOptions }) => {
props.item.value = selectedValues[0] + '-' + selectedValues[1];
props.item.value = selectedValues[0] + "-" + selectedValues[1];
showPicker.value = false;
};
onMounted(() => {
currentDate.value = props.item.value.split('-')
})
currentDate.value = props.item.value.split("-");
});
</script>
<style lang="less" scoped>
......
......@@ -7,13 +7,31 @@
-->
<template>
<div class="datetime-picker">
<div class="label">{{ item.component_props.label }}<span v-if="item.component_props.required">&nbsp;*</span></div>
<van-field v-model="item.value" is-link readonly :name="item.key" :required="item.required"
:placeholder="item.component_props.placeholder" :rules="item.rules" @click="showPicker = true" />
<div class="label">
{{ item.component_props.label }}
<span v-if="item.component_props.required">&nbsp;*</span>
</div>
<van-field
v-model="item.value"
is-link
readonly
:name="item.key"
:required="item.component_props.required"
:placeholder="item.component_props.placeholder"
:rules="item.rules"
@click="showPicker = true"
/>
<van-popup v-model:show="showPicker" position="bottom">
<van-picker-group :title="item.component_props.title" :tabs="['选择日期', '选择时间']" @confirm="onConfirm"
@cancel="onCancel">
<van-date-picker v-model="currentDate" :min-date="item.component_props.minDate" />
<van-picker-group
:title="item.component_props.title"
:tabs="['选择日期', '选择时间']"
@confirm="onConfirm"
@cancel="onCancel"
>
<van-date-picker
v-model="currentDate"
:min-date="item.component_props.min_date"
/>
<van-time-picker v-model="currentTime" />
</van-picker-group>
</van-popup>
......@@ -21,19 +39,19 @@
</template>
<script setup>
import { showToast } from 'vant';
import dayjs from 'dayjs';
import { showToast } from "vant";
import dayjs from "dayjs";
const props = defineProps({
item: Object
})
item: Object,
});
const showPicker = ref(false);
const currentDate = ref([]);
const currentTime = ref([]);
const onConfirm = () => {
props.item.value = `${currentDate.value.join('-')} ${currentTime.value.join(':')}`;
props.item.value = `${currentDate.value.join("-")} ${currentTime.value.join(":")}`;
showPicker.value = false;
};
const onCancel = () => {
......@@ -42,15 +60,15 @@ const onCancel = () => {
onMounted(() => {
// 获取值定位显示
const datetime = props.item.value.split(' ');
currentDate.value = datetime[0]?.split('-');
currentTime.value = datetime[1]?.split(':');
})
const datetime = props.item.value.split(" ");
currentDate.value = datetime[0]?.split("-");
currentTime.value = datetime[1]?.split(":");
});
</script>
<style lang="less" scoped>
.datetime-picker {
.label {
.label {
padding: 1rem 1rem 0 1rem;
font-size: 0.9rem;
font-weight: bold;
......@@ -58,6 +76,6 @@ onMounted(() => {
span {
color: red;
}
}
}
}
</style>
......
......@@ -7,28 +7,42 @@
-->
<template>
<div class="rate-field">
<div class="label">{{ item.label }}<span v-if="item.required">&nbsp;*</span></div>
<van-rate v-model="rate_value" :count="item.component_props.count" @change="onChange" style="padding: 1rem;" />
<div v-if="show_empty" class="van-field__error-message" style="padding: 0 1rem 1rem 1rem;">评分不能为空</div>
<div class="label">
{{ item.component_props.label
}}<span v-if="item.component_props.required">&nbsp;*</span>
</div>
<van-rate
v-model="rate_value"
:count="item.component_props.count"
@change="onChange"
style="padding: 1rem"
/>
<div
v-if="show_empty"
class="van-field__error-message"
style="padding: 0 1rem 1rem 1rem"
>
评分不能为空
</div>
</div>
</template>
<script setup>
const props = defineProps({
item: Object
item: Object,
});
const emit = defineEmits(['active']);
const emit = defineEmits(["active"]);
const show_empty = ref(false);
const rate_value = ref(0);
const onChange = () => {
props.item.value = { key: 'rate', value: rate_value.value };
emit('active', props.item.value);
}
props.item.value = { key: props.item.key, value: rate_value.value, type: "rate" };
emit("active", props.item.value);
};
onMounted(() => {
props.item.value = { key: 'rate', value: rate_value.value };
emit('active', props.item.value);
props.item.value = { key: props.item.key, value: rate_value.value, type: "rate" };
emit("active", props.item.value);
});
const validRate = () => {
......@@ -38,8 +52,8 @@ const validRate = () => {
} else {
show_empty.value = false;
}
return !show_empty.value
}
return !show_empty.value;
};
defineExpose({ validRate });
</script>
......
......@@ -7,11 +7,21 @@
-->
<template>
<div class="sign-page">
<div class="label">{{ item.label }}{{ valid }}<span v-if="item.required">&nbsp;*</span></div>
<div style="padding: 1rem; position: relative;">
<div class="label">
{{ item.component_props.label }}{{ valid
}}<span v-if="item.component_props.required">&nbsp;*</span>
</div>
<div style="padding: 1rem; position: relative">
<!-- <div style="padding: 1rem; position: relative; height: 150px; background-color: #FCFCFC;border: 1px solid #EAEAEA; border-radius: 5px;"> -->
<vue-esign ref="esign" class="sign-wrapper" style="" :isCrop="isCrop" :lineWidth="lineWidth"
:lineColor="lineColor" :bgColor.sync="bgColor" />
<vue-esign
ref="esign"
class="sign-wrapper"
style=""
:isCrop="isCrop"
:lineWidth="lineWidth"
:lineColor="lineColor"
:bgColor.sync="bgColor"
/>
<div v-if="show_sign" class="whiteboard">
<div class="text" @click="startSign">
<van-icon name="edit" />&nbsp;点击开始签署电子签名
......@@ -20,7 +30,7 @@
</div>
<div v-if="!show_sign">
<div v-if="show_control" class="control-sign">
<van-row gutter="20" style="padding: 0 1rem;">
<van-row gutter="20" style="padding: 0 1rem">
<van-col :span="12">
<van-button type="default" block @click="handleGenerate">确认签名</van-button>
</van-col>
......@@ -29,83 +39,103 @@
</van-col>
</van-row>
</div>
<div v-else style="padding: 0 1rem;">
<div v-else style="padding: 0 1rem">
<van-button type="danger" block @click="handleReset">删除签名</van-button>
</div>
</div>
<div v-if="show_empty" class="van-field__error-message" style="padding: 0 1rem 1rem 1rem;">电子签名不能为空</div>
<div
v-if="show_empty"
class="van-field__error-message"
style="padding: 0 1rem 1rem 1rem"
>
电子签名不能为空
</div>
</div>
</template>
<script setup>
import { v4 as uuidv4 } from 'uuid';
import { qiniuTokenAPI, qiniuUploadAPI, saveFileAPI } from '@/api/common'
import { showSuccessToast, showFailToast } from 'vant';
import { v4 as uuidv4 } from "uuid";
import { qiniuTokenAPI, qiniuUploadAPI, saveFileAPI } from "@/api/common";
import { showSuccessToast, showFailToast } from "vant";
const props = defineProps({
item: Object
item: Object,
});
const emit = defineEmits(['active']);
const emit = defineEmits(["active"]);
const esign = ref(null);
const lineWidth = ref(6)
const lineColor = ref('#000000')
const bgColor = ref('#FCFCFC')
const isCrop = ref(false)
const show_control = ref(true)
const image_url = ref('')
const show_empty = ref(false)
const lineWidth = ref(6);
const lineColor = ref("#000000");
const bgColor = ref("#FCFCFC");
const isCrop = ref(false);
const show_control = ref(true);
const image_url = ref("");
const show_empty = ref(false);
const handleReset = () => {
// 清空画板
esign.value.reset();
show_control.value = true;
// 删除可能存在的签名
image_url.value = ''
props.item.value = { key: 'sign', value: '' };
emit('active', props.item.value)
}
image_url.value = "";
props.item.value = { key: "sign", value: "" };
emit("active", props.item.value);
};
const handleGenerate = () => {
esign.value.generate()
.then(async res => {
esign.value
.generate()
.then(async (res) => {
// let fileName = "img1.png";
// let file = this.dataURLtoFile(res, fileName);
// console.log("file", file);
let affix = uuidv4();
let base64url = res.slice(res.indexOf(',') + 1); // 截取前缀的base64 data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAnoAAAJeCAYAA.......
let base64url = res.slice(res.indexOf(",") + 1); // 截取前缀的base64 data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAnoAAAJeCAYAA.......
// 获取七牛token
const { token, key, code } = await qiniuTokenAPI({ filename: `${affix}_sign`, file: base64url });
const { token, key, code } = await qiniuTokenAPI({
filename: `${affix}_sign`,
file: base64url,
});
if (code) {
const config = {
headers: {
'Content-Type': 'application/octet-stream',
'Authorization': 'UpToken ' + token, // UpToken后必须有一个 ' '(空格)
}
}
"Content-Type": "application/octet-stream",
Authorization: "UpToken " + token, // UpToken后必须有一个 ' '(空格)
},
};
// 上传七牛服务器
const { filekey, hash, image_info } = await qiniuUploadAPI('http://upload.qiniup.com/putb64/-1/key/' + key, base64url, config)
const { filekey, hash, image_info } = await qiniuUploadAPI(
"http://upload.qiniup.com/putb64/-1/key/" + key,
base64url,
config
);
if (filekey) {
// 保存图片
const { data } = await saveFileAPI({ filekey, hash, format: image_info.format, height: image_info.height, width: image_info.width });
props.item.value = { key: 'sign', value: data.src};
const { data } = await saveFileAPI({
filekey,
hash,
format: image_info.format,
height: image_info.height,
width: image_info.width,
});
props.item.value = { key: "sign", value: data.src };
image_url.value = data.src;
show_control.value = false;
show_empty.value = false;
emit('active', props.item.value)
emit("active", props.item.value);
}
}
})
.catch(err => {
.catch((err) => {
// 签名生成失败
console.warn(err);
if (err) {
showFailToast('签名生成失败');
showFailToast("签名生成失败");
}
})
}
});
};
//将图片base64转换为文件
const dataURLtoFile = (dataurl, filename) => {
......@@ -118,18 +148,18 @@ const dataURLtoFile = (dataurl, filename) => {
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, { type: mime });
}
};
const show_sign = ref(true);
const startSign = () => {
show_sign.value = false;
show_empty.value = false;
}
};
const cancelSign = () => {
show_sign.value = true;
show_empty.value = false;
handleReset()
}
handleReset();
};
const validSign = () => {
// 必填项 未生成签名
......@@ -138,8 +168,8 @@ const validSign = () => {
} else {
show_empty.value = false;
}
return !show_empty.value
}
return !show_empty.value;
};
defineExpose({ validSign });
</script>
......@@ -154,7 +184,6 @@ export default {
}
</script> -->
<style lang="less" scoped>
.sign-page {
// padding-bottom: 1rem;
......@@ -168,7 +197,7 @@ export default {
}
}
.sign-wrapper {
border: 1px solid #EAEAEA;
border: 1px solid #eaeaea;
border-radius: 5px;
}
.whiteboard {
......
......@@ -7,34 +7,50 @@
-->
<template>
<div class="time-picker-field">
<div class="label">{{ item.label }}<span v-if="item.required">&nbsp;*</span></div>
<van-field v-model="item.value" is-link readonly :name="item.key" :required="item.required"
:placeholder="item.placeholder" :rules="item.rules" @click="showPicker = true" />
<div class="label">
{{ item.component_props.label
}}<span v-if="item.component_props.required">&nbsp;*</span>
</div>
<van-field
v-model="item.value"
is-link
readonly
:name="item.key"
:required="item.component_props.required"
:placeholder="item.component_props.placeholder"
:rules="item.rules"
@click="showPicker = true"
/>
<van-popup v-model:show="showPicker" position="bottom">
<van-time-picker v-model="currentTime" :title="item.component_props.title" :columns-type="item.component_props.columns_type" @confirm="onConfirm"
@cancel="showPicker = false" />
<van-time-picker
v-model="currentTime"
:title="item.component_props.title"
:columns-type="item.component_props.columns_type"
@confirm="onConfirm"
@cancel="showPicker = false"
/>
</van-popup>
</div>
</template>
<script setup>
import dayjs from 'dayjs';
import dayjs from "dayjs";
const props = defineProps({
item: Object
})
item: Object,
});
const showPicker = ref(false);
const currentTime = ref([]);
const onConfirm = ({ selectedValues, selectedOptions }) => {
props.item.value = selectedValues[0] + ':' + selectedValues[1];
props.item.value = selectedValues[0] + ":" + selectedValues[1];
showPicker.value = false;
};
onMounted(() => {
currentTime.value = props.item.value.split(':')
})
currentTime.value = props.item.value.split(":");
});
</script>
<style lang="less" scoped>
......
......@@ -97,7 +97,6 @@ const sign = ref(null);
const rate_picker = ref(null);
const onSubmit = async (values) => {
console.warn(values);
// 合并自定义字段到提交表单字段
postData.value = _.assign(postData.value, values);
// 检查非表单输入项
......@@ -112,6 +111,7 @@ const onSubmit = async (values) => {
// console.warn("提交成功");
// console.warn(data);
// }
console.warn(postData.value);
console.warn("通过验证");
} else {
console.warn("不通过验证");
......@@ -123,8 +123,8 @@ const onActive = (item) => {
if (item.key === "sign") {
postData.value["sign"] = item.value;
}
if (item.key === "rate") {
postData.value["rate"] = item.value;
if (item.type === "rate") {
postData.value = _.assign(postData.value, { [item.key]: item.value });
}
};
......