Toggle navigation
Toggle navigation
This project
Loading...
Sign in
Hooke
/
data-table
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Graphs
Network
Create a new issue
Commits
Issue Boards
Authored by
hookehuyr
2022-11-18 17:37:02 +0800
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
c5c67b671dfaf2dddcf512983eb2c8589ef16e5d
c5c67b67
1 parent
e1c91b01
数据结构适配调整
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
265 additions
and
153 deletions
src/components/CalendarField/index.vue
src/components/DatePickerField/index.vue
src/components/DateTimePickerField/index.vue
src/components/RatePickerField/index.vue
src/components/SignField/index.vue
src/components/TimePickerField/index.vue
src/views/index.vue
src/components/CalendarField/index.vue
View file @
c5c67b6
...
...
@@ -7,39 +7,58 @@
-->
<template>
<div class="calendar-page">
<div class="label">{{ item.label }}<span v-if="item.required"> *</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"> *</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>
...
...
src/components/DatePickerField/index.vue
View file @
c5c67b6
...
...
@@ -7,35 +7,52 @@
-->
<template>
<div class="date-picker-field">
<div class="label">{{ item.label }}<span v-if="item.required"> *</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"> *</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>
...
...
src/components/DateTimePickerField/index.vue
View file @
c5c67b6
...
...
@@ -7,13 +7,31 @@
-->
<template>
<div class="datetime-picker">
<div class="label">{{ item.component_props.label }}<span v-if="item.component_props.required"> *</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"> *</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,22 +60,22 @@ 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 {
padding: 1rem 1rem 0 1rem;
font-size: 0.9rem;
font-weight: bold;
.label {
padding: 1rem 1rem 0 1rem;
font-size: 0.9rem;
font-weight: bold;
span {
color: red;
span {
color: red;
}
}
}
}
</style>
...
...
src/components/RatePickerField/index.vue
View file @
c5c67b6
...
...
@@ -7,28 +7,42 @@
-->
<template>
<div class="rate-field">
<div class="label">{{ item.label }}<span v-if="item.required"> *</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"> *</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>
...
...
src/components/SignField/index.vue
View file @
c5c67b6
...
...
@@ -7,11 +7,21 @@
-->
<template>
<div class="sign-page">
<div class="label">{{ item.label }}{{ valid }}<span v-if="item.required"> *</span></div>
<div style="padding: 1rem; position: relative;">
<div class="label">
{{ item.component_props.label }}{{ valid
}}<span v-if="item.component_props.required"> *</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" /> 点击开始签署电子签名
...
...
@@ -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 => {
// 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.......
// 获取七牛token
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后必须有一个 ' '(空格)
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.......
// 获取七牛token
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后必须有一个 ' '(空格)
},
};
// 上传七牛服务器
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 };
image_url.value = data.src;
show_control.value = false;
show_empty.value = false;
emit("active", props.item.value);
}
}
// 上传七牛服务器
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};
image_url.value = data.src;
show_control.value = false;
show_empty.value = false;
emit('active', props.item.value)
})
.catch((err) => {
// 签名生成失败
console.warn(err);
if (err) {
showFailToast("签名生成失败");
}
}
})
.catch(err => {
// 签名生成失败
console.warn(err);
if (err) {
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 {
...
...
src/components/TimePickerField/index.vue
View file @
c5c67b6
...
...
@@ -7,34 +7,50 @@
-->
<template>
<div class="time-picker-field">
<div class="label">{{ item.label }}<span v-if="item.required"> *</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"> *</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>
...
...
src/views/index.vue
View file @
c5c67b6
...
...
@@ -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 })
;
}
};
...
...
Please
register
or
login
to post a comment