Commit 373a242f authored by 李明环(东信)'s avatar 李明环(东信)

表单组件 创建工作步骤1

parent 10eb7e7a
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
"files.eol": "\n", "files.eol": "\n",
"typescript.tsdk": "node_modules/typescript/lib", "typescript.tsdk": "node_modules/typescript/lib",
"[vue]": { "[vue]": {
"editor.defaultFormatter": "octref.vetur" "editor.defaultFormatter": "esbenp.prettier-vscode"
}, },
"[typescript]": { "[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode" "editor.defaultFormatter": "esbenp.prettier-vscode"
......
<template>
<div class="form-item" :style="{ borderWidth: props.border ? '2rpx' : '0' }">
<p class="title">{{ props.title }}</p>
<img v-if="icon" class="icon" :src="iconPath" alt="" />
<slot></slot>
</div>
</template>
<script setup lang="ts">
const props = defineProps({
// 标题
title: {
type: String,
default: () => "默认title"
},
// 边框
border: {
type: Boolean,
default: () => true
},
// 图标 (如果为空不显示)
icon: {
type: String as PropType<"arrow" | "edit" | "">,
default: () => "arrow"
}
});
const iconPath = new URL(`../../static/image/icon/${props.icon}.png`, import.meta.url).href;
</script>
<style lang="scss" scoped>
.form-item {
position: relative;
padding-bottom: 16rpx;
margin-top: 32rpx;
border-bottom: 2rpx solid rgb(31 35 41 / 15%);
.title {
margin-bottom: 32rpx;
font-size: 32rpx;
font-weight: 600;
line-height: 36rpx;
}
.icon {
position: absolute;
right: 20rpx;
bottom: 24rpx;
width: 28rpx;
height: 28rpx;
}
}
</style>
<template>
<div class="form-row" :style="{ gridTemplateColumns: props.fill ? '1fr' : '1fr 1fr' }">
<slot></slot>
</div>
</template>
<script setup>
const props = defineProps({
fill: {
type: Boolean,
default: () => true
}
});
</script>
<style lang="scss" scoped>
.form-row {
display: grid;
}
</style>
<template>
<div class="selectbox">
<div
v-for="v in props.options"
:class="{ item: true, active: isActive(v) }"
:key="v[props.valueKey]"
@click="onClickItem(v)"
>
{{ v[props.labelKey] }}
</div>
</div>
</template>
<script setup>
const props = defineProps({
// 默认值
modelValue: {
type: [String, Number, Array],
default: () => ""
},
//值的键
valueKey: {
type: String,
default: () => "value"
},
//label的键
labelKey: {
type: String,
default: () => "label"
},
// 是否多选
multiple: {
type: Boolean,
default: () => false
},
// 默认值
options: {
type: Array,
default: () => []
}
});
const emit = defineEmits(["update:modelValue"]);
// 激活类名
const isActive = e => {
if (props.multiple) {
return props.modelValue.includes(e[props.valueKey]);
} else {
return props.modelValue === e[props.valueKey];
}
};
// 点击选项
const onClickItem = e => {
const value = e[props.valueKey];
if (props.multiple) {
const index = props.modelValue.indexOf(value);
if (index > -1) {
emit("update:modelValue", props.modelValue.slice(index, 1));
} else {
emit("update:modelValue", [...props.modelValue, value]);
}
} else {
emit("update:modelValue", value);
}
};
</script>
<style lang="scss" scoped>
.selectbox {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 8px;
.item {
display: flex;
align-items: center;
justify-content: center;
height: 32px;
font-size: 12px;
color: #1f86ff;
background: #1f86ff0f;
border-radius: 4px;
}
.active {
color: #ffffff;
background: #1f86ff;
}
}
</style>
@import "wot-design-uni/components/common/abstracts/variable";
@import "wot-design-uni/components/common/abstracts/mixin";
.wot-theme-dark {
@include b(col-picker) {
@include when(border) {
.wd-col-picker__cell {
@include halfPixelBorder("top", $-cell-padding, $-dark-border-color);
}
}
@include e(label) {
color: $-dark-color;
}
@include e(cell) {
color: $-dark-color;
background-color: $-dark-background2;
@include when(disabled) {
.wd-col-picker__value {
color: $-dark-color3;
}
}
}
@include e(list-item) {
@include when(disabled) {
color: $-dark-color3;
}
}
@include e(list-item-tip) {
color: $-dark-color-gray;
}
@include e(value) {
color: $-dark-color;
@include m(placeholder) {
color: $-dark-color-gray;
}
}
:deep(.wd-col-picker__arrow) {
color: $-dark-color;
}
@include e(list) {
color: $-dark-color;
}
@include e(selected) {
color: $-dark-color;
}
}
}
.tags {
gap: 32rpx;
padding: 0 32rpx;
div {
padding: 8rpx 16rpx;
font-size: 24rpx;
color: #4d80f0;
background-color: #4d80f01f;
}
}
@include b(col-picker) {
@include when(border) {
.wd-col-picker__cell {
@include halfPixelBorder("top", $-cell-padding);
}
}
@include e(cell) {
position: relative;
display: flex;
align-items: flex-start;
padding: $-cell-wrapper-padding $-cell-padding;
overflow: hidden;
font-size: $-cell-title-fs;
line-height: $-cell-line-height;
color: $-cell-title-color;
text-decoration: none;
background-color: $-color-white;
}
@include e(cell) {
@include when(disabled) {
.wd-col-picker__value {
color: $-input-disabled-color;
}
}
@include when(align-right) {
.wd-col-picker__value {
text-align: right;
}
}
@include when(error) {
.wd-col-picker__value {
color: $-input-error-color;
}
:deep(.wd-col-picker__arrow) {
color: $-input-error-color;
}
}
@include when(large) {
font-size: $-cell-title-fs-large;
:deep(.wd-col-picker__arrow) {
font-size: $-cell-icon-size-large;
}
}
}
@include e(error-message) {
font-size: $-form-item-error-message-font-size;
line-height: $-form-item-error-message-line-height;
color: $-form-item-error-message-color;
text-align: left;
vertical-align: middle;
}
@include e(label) {
position: relative;
box-sizing: border-box;
width: $-input-cell-label-width;
margin-right: $-cell-padding;
color: $-cell-title-color;
@include when(required) {
padding-left: 12px;
&::after {
position: absolute;
top: 2px;
left: 0;
font-size: $-cell-required-size;
line-height: 1.1;
color: $-cell-required-color;
content: "*";
}
}
}
@include e(value-wraper) {
display: flex;
}
@include e(value) {
flex: 1;
margin-right: 10px;
color: $-cell-value-color;
@include when(ellipsis) {
@include lineEllipsis;
}
@include m(placeholder) {
color: $-input-placeholder-color;
}
}
@include e(body) {
flex: 1;
}
@include edeep(arrow) {
display: block;
font-size: $-cell-icon-size;
line-height: $-cell-line-height;
color: $-cell-arrow-color;
}
@include e(selected) {
height: $-col-picker-selected-height;
overflow: hidden;
font-size: $-col-picker-selected-fs;
color: $-col-picker-selected-color;
}
@include e(selected-container) {
position: relative;
display: flex;
user-select: none;
}
@include e(selected-item) {
flex: 0 0 auto;
height: $-col-picker-selected-height;
padding: $-col-picker-selected-padding;
line-height: $-col-picker-selected-height;
@include when(selected) {
font-weight: $-col-picker-selected-fw;
}
}
@include e(selected-line) {
position: absolute;
bottom: 5px;
left: 0;
z-index: 1;
width: $-col-picker-line-width;
height: $-col-picker-line-height;
background: $-col-picker-line-color;
border-radius: calc($-col-picker-line-height / 2);
box-shadow: $-col-picker-line-box-shadow;
}
@include e(list-container) {
position: relative;
}
@include e(list) {
box-sizing: border-box;
height: $-col-picker-list-height;
padding-bottom: $-col-picker-list-padding-bottom;
overflow: auto;
font-size: $-col-picker-list-fs;
color: $-col-picker-list-color;
-webkit-overflow-scrolling: touch;
}
@include e(list-item) {
display: flex;
align-items: flex-start;
padding: $-col-picker-list-item-padding;
@include when(selected) {
color: $-col-picker-list-color-checked;
:deep(.wd-col-picker__checked) {
opacity: 1;
}
}
@include when(disabled) {
color: $-col-picker-list-color-disabled;
}
}
@include e(list-item-label) {
line-height: 1.285;
}
@include e(list-item-tip) {
margin-top: 2px;
font-size: $-col-picker-list-fs-tip;
color: $-col-picker-list-color-tip;
}
@include edeep(checked) {
display: block;
margin-left: 4px;
font-size: $-col-picker-list-checked-icon-size;
color: $-col-picker-list-color-checked;
opacity: 0;
}
@include e(loading) {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
}
}
import type { ComponentPublicInstance, ExtractPropTypes, PropType } from "vue";
import {
baseProps,
makeArrayProp,
makeBooleanProp,
makeNumberProp,
makeRequiredProp,
makeStringProp
} from "wot-design-uni/components/common/props";
import type { FormItemRule } from "wot-design-uni/components/wd-form/types";
export const colPickerProps = {
...baseProps,
/**
* 选中项
*/
modelValue: makeRequiredProp(Array as PropType<Array<string | number>>),
/* 多选数据 */
mValue: {
type: Array,
default: () => []
},
mMax: {
type: Number,
default: 1
},
/**
* 选择器数据,二维数组
*/
columns: makeArrayProp<Record<string, any>[]>(),
/**
* 选择器左侧文案
*/
label: String,
/**
* 设置左侧标题宽度
*/
labelWidth: makeStringProp("33%"),
/**
* 使用 label 插槽时设置该选项
*/
useLabelSlot: makeBooleanProp(false),
/**
* 使用默认插槽时设置该选项
*/
useDefaultSlot: makeBooleanProp(false),
/**
* 禁用
*/
disabled: makeBooleanProp(false),
/**
* 只读
*/
readonly: makeBooleanProp(false),
/**
* 选择器占位符
*/
placeholder: String,
/**
* 弹出层标题
*/
title: String,
/**
* 接收当前列的选中项 item、当前列下标、当前列选中项下标下一列数据处理函数 resolve、结束选择 finish
*/
columnChange: Function as PropType<ColPickerColumnChange>,
/**
* 自定义展示文案的格式化函数,返回一个字符串
*/
displayFormat: Function as PropType<ColPickerDisplayFormat>,
/**
* 确定前校验函数,接收 (value, resolve) 参数,通过 resolve 继续执行 picker,resolve 接收 1 个 boolean 参数
*/
beforeConfirm: Function as PropType<ColPickerBeforeConfirm>,
/**
* 选择器的值靠右展示
*/
alignRight: makeBooleanProp(false),
/**
* 是否为错误状态,错误状态时右侧内容为红色
*/
error: makeBooleanProp(false),
/**
* 是否必填
*/
required: makeBooleanProp(false),
/**
* 设置选择器大小,可选值:large
*/
size: String,
/**
* 选项对象中,value 对应的 key
*/
valueKey: makeStringProp("value"),
/**
* 选项对象中,展示的文本对应的 key
*/
labelKey: makeStringProp("label"),
/**
* 选项对象中,提示文案对应的 key
*/
tipKey: makeStringProp("tip"),
/**
* loading 图标的颜色
*/
loadingColor: makeStringProp("#4D80F0"),
/**
* 点击遮罩是否关闭
*/
closeOnClickModal: makeBooleanProp(true),
/**
* 自动触发 column-change 事件来补全数据,当 columns 为空数组或者 columns 数组长度小于 value 数组长度时,会自动触发 column-change
*/
autoComplete: makeBooleanProp(false),
/**
* 弹窗层级
*/
zIndex: makeNumberProp(15),
/**
* 弹出面板是否设置底部安全距离(iphone X 类型的机型)
*/
safeAreaInsetBottom: makeBooleanProp(true),
/**
* 是否超出隐藏
*/
ellipsis: makeBooleanProp(false),
/**
* 表单域 model 字段名,在使用表单校验功能的情况下,该属性是必填的
*/
prop: String,
/**
* 表单验证规则,结合wd-form组件使用
*/
rules: makeArrayProp<FormItemRule>(),
/**
* label 外部自定义样式
*/
customViewClass: makeStringProp(""),
/**
* value 外部自定义样式
*/
customLabelClass: makeStringProp(""),
customValueClass: makeStringProp("")
};
export type ColPickerProps = ExtractPropTypes<typeof colPickerProps>;
export type ColPickerColumnChangeOption = {
selectedItem: Record<string, any>;
index: number;
rowIndex: number;
addMValue: Function;
resolve: (nextColumn: Record<string, any>[]) => void;
finish: (isOk?: boolean) => void;
};
export type ColPickerColumnChange = (option: ColPickerColumnChangeOption) => void;
export type ColPickerDisplayFormat = (selectedItems: Record<string, any>[]) => string;
export type ColPickerBeforeConfirm = (
value: (string | number)[],
selectedItems: Record<string, any>[],
resolve: (isPass: boolean) => void
) => void;
export type ColPickerExpose = {
// 关闭picker弹框
close: () => void;
// 打开picker弹框
open: () => void;
};
export type ColPickerInstance = ComponentPublicInstance<ColPickerExpose, ColPickerProps>;
<template>
<view :class="`wd-col-picker ${cell.border.value ? 'is-border' : ''} ${customClass}`" :style="customStyle">
<view class="wd-col-picker__field" @click="showPicker">
<slot v-if="useDefaultSlot"></slot>
<view
v-else
:class="`wd-col-picker__cell ${disabled && 'is-disabled'} ${readonly && 'is-readonly'} ${
alignRight && 'is-align-right'
} ${error && 'is-error'} ${size && 'is-' + size}`"
>
<view
v-if="label || useLabelSlot"
:class="`wd-col-picker__label ${isRequired && 'is-required'} ${customLabelClass}`"
:style="labelWidth ? 'min-width:' + labelWidth + ';max-width:' + labelWidth + ';' : ''"
>
<block v-if="label">{{ label }}</block>
<slot v-else name="label"></slot>
</view>
<view class="wd-col-picker__body">
<view class="wd-col-picker__value-wraper">
<view
:class="`wd-col-picker__value ${ellipsis && 'is-ellipsis'} ${customValueClass} ${
showValue ? '' : 'wd-col-picker__value--placeholder'
}`"
>
{{ showValue || placeholder || translate("placeholder") }}
</view>
<wd-icon v-if="!disabled && !readonly" custom-class="wd-col-picker__arrow" name="arrow-right" />
</view>
<view v-if="errorMessage" class="wd-col-picker__error-message">{{ errorMessage }}</view>
</view>
</view>
</view>
<wd-action-sheet
v-model="pickerShow"
:duration="250"
:title="title || translate('title')"
:close-on-click-modal="closeOnClickModal"
:z-index="zIndex"
:safe-area-inset-bottom="safeAreaInsetBottom"
@open="handlePickerOpend"
@close="handlePickerClose"
>
<view class="flex-align-center tags">
<div v-for="(item, index) in mValue" :key="index" type="primary">{{ item.name }}</div>
</view>
<view class="wd-col-picker__selected">
<scroll-view :scroll-x="true" scroll-with-animation :scroll-left="scrollLeft">
<view class="wd-col-picker__selected-container">
<view
v-for="(select, colIndex) in selectList"
:key="colIndex"
:class="`wd-col-picker__selected-item ${colIndex === currentCol && 'is-selected'}`"
@click="handleColClick(colIndex)"
>
{{ selectShowList[colIndex] || translate("select") }}
</view>
<view class="wd-col-picker__selected-line" :style="lineStyle"></view>
</view>
</scroll-view>
</view>
<view class="wd-col-picker__list-container">
<view
v-for="(col, colIndex) in selectList"
:key="colIndex"
class="wd-col-picker__list"
:style="colIndex === currentCol ? 'display: block;' : 'display: none;'"
>
<view
v-for="(item, index) in col"
:key="index"
:class="`wd-col-picker__list-item ${item.disabled && 'is-disabled'} ${
mValue.some(v => v[valueKey] == item[valueKey]) && 'is-selected'
}`"
@click="chooseItem(colIndex, index)"
>
<!-- ${pickerColSelected[colIndex] && item[valueKey] === pickerColSelected[colIndex] && 'is-selected'} -->
<view>
<view class="wd-col-picker__list-item-label"> {{ item[labelKey] }}</view>
<view v-if="item[tipKey]" class="wd-col-picker__list-item-tip">{{ item[tipKey] }}</view>
</view>
<wd-icon custom-class="wd-col-picker__checked" name="check"></wd-icon>
</view>
<view v-if="loading" class="wd-col-picker__loading">
<wd-loading :color="loadingColor" />
</view>
</view>
</view>
</wd-action-sheet>
</view>
</template>
<script lang="ts">
export default {
name: "col-picker",
options: {
addGlobalClass: true,
virtualHost: true,
styleIsolation: "shared"
}
};
</script>
<script lang="ts" setup>
import { computed, getCurrentInstance, onMounted, ref, watch } from "vue";
import { debounce, getRect, isArray, isBoolean, isFunction } from "wot-design-uni/components/common/util";
import { useCell } from "wot-design-uni/components/composables/useCell";
import { FORM_KEY, type FormItemRule } from "wot-design-uni/components/wd-form/types";
import { useParent } from "wot-design-uni/components/composables/useParent";
import { useTranslate } from "wot-design-uni/components/composables/useTranslate";
import { colPickerProps, type ColPickerExpose } from "./types";
const { translate } = useTranslate("col-picker");
const $container = ".wd-col-picker__selected-container";
const $item = ".wd-col-picker__selected-item";
const props = defineProps(colPickerProps);
console.log(props.mMax);
console.log(props.mValue);
const emit = defineEmits(["close", "update:modelValue", "update:mValue", "confirm"]);
const pickerShow = ref<boolean>(false);
const currentCol = ref<number>(0);
const selectList = ref<Record<string, any>[][]>([]);
const pickerColSelected = ref<(string | number)[]>([]);
const selectShowList = ref<Record<string, any>[]>([]);
const loading = ref<boolean>(false);
const isChange = ref<boolean>(false);
const lastSelectList = ref<Record<string, any>[][]>([]);
const lastPickerColSelected = ref<(string | number)[]>([]);
const lineStyle = ref<string>("");
const scrollLeft = ref<number>(0);
const inited = ref<boolean>(false);
const isCompleting = ref<boolean>(false);
const { proxy } = getCurrentInstance() as any;
const cell = useCell();
const updateLineAndScroll = debounce(function (animation = true) {
setLineStyle(animation);
lineScrollIntoView();
}, 50);
const showValue = computed(() => {
const selectedItems = (props.modelValue || []).map((item, colIndex) => {
return getSelectedItem(item, colIndex, selectList.value);
});
if (props.displayFormat) {
return props.displayFormat(selectedItems);
} else {
return selectedItems
.map(item => {
return item[props.labelKey];
})
.join("");
}
});
watch(
() => props.modelValue,
newValue => {
if (newValue === pickerColSelected.value) return;
pickerColSelected.value = newValue;
newValue.map((item, colIndex) => {
return getSelectedItem(item, colIndex, selectList.value)[props.labelKey];
});
handleAutoComplete();
},
{
deep: true,
immediate: true
}
);
watch(
() => props.columns,
(newValue, oldValue) => {
if (newValue.length && !isArray(newValue[0])) {
console.error(
"[wot design] error(wd-col-picker): the columns props of wd-col-picker should be a two-dimensional array"
);
return;
}
if (newValue.length === 0 && !oldValue) return;
const newSelectedList = newValue.slice(0);
selectList.value = newSelectedList;
selectShowList.value = pickerColSelected.value.map((item, colIndex) => {
return getSelectedItem(item, colIndex, newSelectedList)[props.labelKey];
});
lastSelectList.value = newSelectedList;
if (newSelectedList.length > 0) {
currentCol.value = newSelectedList.length - 1;
}
},
{
deep: true,
immediate: true
}
);
watch(
() => props.columnChange,
fn => {
if (fn && !isFunction(fn)) {
console.error("The type of columnChange must be Function");
}
},
{
deep: true,
immediate: true
}
);
watch(
() => props.displayFormat,
fn => {
if (fn && !isFunction(fn)) {
console.error("The type of displayFormat must be Function");
}
},
{
deep: true,
immediate: true
}
);
watch(
() => props.beforeConfirm,
fn => {
if (fn && !isFunction(fn)) {
console.error("The type of beforeConfirm must be Function");
}
},
{
deep: true,
immediate: true
}
);
const { parent: form } = useParent(FORM_KEY);
// 表单校验错误信息
const errorMessage = computed(() => {
if (form && props.prop && form.errorMessages && form.errorMessages[props.prop]) {
return form.errorMessages[props.prop];
} else {
return "";
}
});
// 是否展示必填
const isRequired = computed(() => {
let formRequired = false;
if (form && form.props.rules) {
const rules = form.props.rules;
for (const key in rules) {
if (Object.prototype.hasOwnProperty.call(rules, key) && key === props.prop && Array.isArray(rules[key])) {
formRequired = rules[key].some((rule: FormItemRule) => rule.required);
}
}
}
return props.required || props.rules.some(rule => rule.required) || formRequired;
});
onMounted(() => {
inited.value = true;
});
// 打开弹框
function open() {
showPicker();
}
// 关闭弹框
function close() {
handlePickerClose();
}
function handlePickerOpend() {
updateLineAndScroll(false);
}
function handlePickerClose() {
pickerShow.value = false;
// 如果目前用户正在选择,需要在popup关闭时将数据重置回上次数据,popup 关闭时间 250
if (isChange.value) {
setTimeout(() => {
selectList.value = lastSelectList.value.slice(0);
pickerColSelected.value = lastPickerColSelected.value.slice(0);
selectShowList.value = lastPickerColSelected.value.map((item, colIndex) => {
return getSelectedItem(item, colIndex, lastSelectList.value)[props.labelKey];
});
currentCol.value = lastSelectList.value.length - 1;
isChange.value = false;
}, 250);
}
emit("close");
}
function showPicker() {
const { disabled, readonly } = props;
if (disabled || readonly) return;
pickerShow.value = true;
lastPickerColSelected.value = pickerColSelected.value.slice(0);
lastSelectList.value = selectList.value.slice(0);
}
function getSelectedItem(value: string | number, colIndex: number, selectList: Record<string, any>[][]) {
const { valueKey, labelKey } = props;
if (selectList[colIndex]) {
const selecteds = selectList[colIndex].filter(item => {
return item[valueKey] === value;
});
if (selecteds.length > 0) {
return selecteds[0];
}
}
return {
[valueKey]: value,
[labelKey]: ""
};
}
function chooseItem(colIndex: number, index: number) {
const item = selectList.value[colIndex][index];
if (item.disabled) return;
const newPickerColSelected = pickerColSelected.value.slice(0, colIndex);
newPickerColSelected.push(item[props.valueKey]);
isChange.value = true;
pickerColSelected.value = newPickerColSelected;
selectList.value = selectList.value.slice(0, colIndex + 1);
selectShowList.value = newPickerColSelected.map((item, colIndex) => {
return getSelectedItem(item, colIndex, selectList.value)[props.labelKey];
});
handleColChange(colIndex, item, index);
}
function handleColChange(colIndex: number, item: Record<string, any>, index: number, callback?: () => void) {
loading.value = true;
const { columnChange, beforeConfirm } = props;
columnChange &&
columnChange({
selectedItem: item,
index: colIndex,
rowIndex: index,
resolve: (nextColumn: Record<string, any>[]) => {
if (!isArray(nextColumn)) {
console.error(
"[wot design] error(wd-col-picker): the data of each column of wd-col-picker should be an array"
);
return;
}
const newSelectList = selectList.value.slice(0);
newSelectList[colIndex + 1] = nextColumn;
selectList.value = newSelectList;
loading.value = false;
currentCol.value = colIndex + 1;
updateLineAndScroll(true);
if (typeof callback === "function") {
isCompleting.value = false;
selectShowList.value = pickerColSelected.value.map((item, colIndex) => {
return getSelectedItem(item, colIndex, selectList.value)[props.labelKey];
});
callback();
}
},
addMValue: value => {
emit("update:mValue", [...props.mValue, value]);
},
finish: (isOk?: boolean) => {
// 每设置展示数据回显
if (typeof callback === "function") {
loading.value = false;
isCompleting.value = false;
return;
}
if (isBoolean(isOk) && !isOk) {
loading.value = false;
return;
}
if (beforeConfirm) {
beforeConfirm(
pickerColSelected.value,
pickerColSelected.value.map((item, colIndex) => {
return getSelectedItem(item, colIndex, selectList.value);
}),
(isPass: boolean) => {
if (isPass) {
onConfirm();
} else {
loading.value = false;
}
}
);
} else {
onConfirm();
}
}
});
}
function onConfirm() {
isChange.value = false;
loading.value = false;
pickerShow.value = false;
emit("update:modelValue", pickerColSelected.value);
emit("confirm", {
value: pickerColSelected.value,
selectedItems: pickerColSelected.value.map((item, colIndex) => {
return getSelectedItem(item, colIndex, selectList.value);
})
});
}
function handleColClick(index: number) {
isChange.value = true;
currentCol.value = index;
updateLineAndScroll(true);
}
/**
* @description 更新navBar underline的偏移量
* @param {Boolean} animation 是否伴随动画
*/
function setLineStyle(animation = true) {
if (!inited.value) return;
getRect($item, true, proxy).then(rects => {
const rect = rects[currentCol.value];
// const width = lineWidth || (slidableNum < items.length ? rect.width : (rect.width - 14))
const width = 16;
let left = rects.slice(0, currentCol.value).reduce((prev: any, curr: any) => prev + curr.width, 0);
left += (Number(rect.width) - width) / 2;
const transition = animation ? "transition: width 300ms ease, transform 300ms ease;" : "";
const lineStyleTemp = `
transform: translateX(${left}px);
${transition}
`;
// 防止重复绘制
if (lineStyle.value !== lineStyleTemp) {
lineStyle.value = lineStyleTemp;
}
});
}
/**
* @description scroll-view滑动到active的tab_nav
*/
function lineScrollIntoView() {
if (!inited.value) return;
Promise.all([getRect($item, true, proxy), getRect($container, false, proxy)]).then(([navItemsRects, navRect]) => {
if (!isArray(navItemsRects) || navItemsRects.length === 0) return;
// 选中元素
const selectItem = navItemsRects[currentCol.value];
// 选中元素之前的节点的宽度总和
const offsetLeft = navItemsRects.slice(0, currentCol.value).reduce((prev, curr) => prev + Number(curr.width), 0);
// scroll-view滑动到selectItem的偏移量
scrollLeft.value = offsetLeft - ((navRect as any).width - Number(selectItem.width)) / 2;
});
}
// 递归列数据补齐
function diffColumns(colIndex: number) {
// colIndex 为 -1 时,item 为空对象,>=0 时则具有 value 属性
const item = colIndex === -1 ? {} : { [props.valueKey]: props.modelValue[colIndex] };
handleColChange(colIndex, item, -1, () => {
// 如果 columns 长度还小于 value 长度,colIndex + 1,继续递归补齐
if (selectList.value.length < props.modelValue.length) {
diffColumns(colIndex + 1);
}
});
}
function handleAutoComplete() {
if (props.autoComplete) {
// 如果 columns 数组长度为空,或者长度小于 value 的长度,自动触发 columnChange 来补齐数据
if (selectList.value.length < props.modelValue.length || selectList.value.length === 0) {
// isCompleting 是否在自动补全,锁操作
if (!isCompleting.value) {
// 如果 columns 长度为空,则传入的 colIndex 为 -1
const colIndex = selectList.value.length === 0 ? -1 : selectList.value.length - 1;
diffColumns(colIndex);
}
isCompleting.value = true;
}
}
}
defineExpose<ColPickerExpose>({
close,
open
});
</script>
<style lang="scss" scoped>
@import "./index.scss";
</style>
...@@ -6,9 +6,35 @@ ...@@ -6,9 +6,35 @@
<view class="t2">选择对应的职位并填写职位信息</view> <view class="t2">选择对应的职位并填写职位信息</view>
</view> </view>
<view class="content"> <view class="content">
<view class="switch"> <selectbox :options="typeOptions" v-model="typeValue"></selectbox>
<!-- <view class="active">全职</view> <form-row>
<view>兼职</view> --> <form-item title="职位类型">
<wd-col-picker
v-model="value"
:columns="columns"
:column-change="columnChange"
@confirm="handleConfirm"
label-key="name"
value-key="id"
use-default-slot
>
<view :class="`inner flex-between ${pinias.formData.jobTypeText ? '' : 'placeholder'}`">
{{ pinias.formData.jobTypeText || "请选择职位类型" }}
</view>
</wd-col-picker>
</form-item>
</form-row>
<form-row>
<form-item title="职位标题" icon="edit">
<input type="text" placeholder="输入职位标题如“财务总监”" />
</form-item>
</form-row>
<form-row>
<form-item title="职位描述" :border="false" icon="">
<textarea></textarea>
</form-item>
</form-row>
<!-- <view class="switch">
<view <view
v-for="(item, index) in EnumWorkMode" v-for="(item, index) in EnumWorkMode"
:class="item.code == pinias.formData.workMode ? 'active' : ''" :class="item.code == pinias.formData.workMode ? 'active' : ''"
...@@ -16,8 +42,8 @@ ...@@ -16,8 +42,8 @@
:key="index" :key="index"
>{{ item.text }} >{{ item.text }}
</view> </view>
</view> </view> -->
<view class="form-item"> <!-- <view class="form-item">
<view class="form-item-title">职位类型</view> <view class="form-item-title">职位类型</view>
<wd-col-picker <wd-col-picker
v-model="value" v-model="value"
...@@ -33,8 +59,8 @@ ...@@ -33,8 +59,8 @@
<view class="arrow"></view> <view class="arrow"></view>
</view> </view>
</wd-col-picker> </wd-col-picker>
</view> </view> -->
<view class="form-item"> <!-- <view class="form-item">
<view class="form-item-title">职位标题</view> <view class="form-item-title">职位标题</view>
<view class="inner flex-between"> <view class="inner flex-between">
<input <input
...@@ -44,8 +70,8 @@ ...@@ -44,8 +70,8 @@
placeholder="请输入职业标题" placeholder="请输入职业标题"
/> />
</view> </view>
</view> </view> -->
<view class="form-item describe" style="border: 0"> <!-- <view class="form-item describe" style="border: 0">
<view class="form-item-title">职位描述</view> <view class="form-item-title">职位描述</view>
<wd-textarea <wd-textarea
custom-class="textarea" custom-class="textarea"
...@@ -54,12 +80,9 @@ ...@@ -54,12 +80,9 @@
v-model="pinias.formData.jobDesc" v-model="pinias.formData.jobDesc"
placeholder="请输入你的职位描述" placeholder="请输入你的职位描述"
/> />
</view> </view> -->
</view> </view>
<!-- <view class="btn-wrap">
<button class="bottom-btn" @tap="next">下一步</button>
</view> -->
<wd-tabbar <wd-tabbar
@tap="next" @tap="next"
custom-style="display: flex;justify-content: center !important;z-index:1;" custom-style="display: flex;justify-content: center !important;z-index:1;"
...@@ -81,6 +104,10 @@ import { validateForm } from "@/utils/utils"; ...@@ -81,6 +104,10 @@ import { validateForm } from "@/utils/utils";
import _ from "lodash"; import _ from "lodash";
import { useReleasePostionStore } from "./store"; import { useReleasePostionStore } from "./store";
import FormItem from "@/components/form/form-item.vue";
import FormRow from "@/components/form/form-row.vue";
import Selectbox from "@/components/form/selectbox.vue";
const pinias = useReleasePostionStore(); const pinias = useReleasePostionStore();
onLoad(option => { onLoad(option => {
...@@ -139,11 +166,33 @@ const next = () => { ...@@ -139,11 +166,33 @@ const next = () => {
}); });
} }
}; };
/* 类型 */
const typeValue = ref(1);
const typeOptions = [
{
label: "全职",
value: 1
},
{
label: "兼职",
value: 2
},
{
label: "见习",
value: 3
},
{
label: "实习",
value: 4
}
];
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@import "./common.scss"; @import "./common.scss";
.describe {
/* .describe {
textarea { textarea {
box-sizing: border-box; box-sizing: border-box;
width: 686rpx; width: 686rpx;
...@@ -156,21 +205,20 @@ const next = () => { ...@@ -156,21 +205,20 @@ const next = () => {
} }
.page { .page {
.textarea { .textarea {
max-height: 272rpx;
margin-top: 32rpx; margin-top: 32rpx;
background: #f2f5fb; background: #f2f5fb;
max-height: 272rpx;
:deep(.wd-textarea__value) { :deep(.wd-textarea__value) {
background: #f2f5fb !important;
max-height: 272rpx;
width: 100%; width: 100%;
max-height: 272rpx;
padding: 0 !important; padding: 0 !important;
background: #f2f5fb !important;
} }
:deep(.wd-textarea__count) { :deep(.wd-textarea__count) {
background: none !important; background: none !important;
} }
} }
} }
.switch { .switch {
display: flex; display: flex;
align-items: center; align-items: center;
...@@ -189,8 +237,14 @@ const next = () => { ...@@ -189,8 +237,14 @@ const next = () => {
background-color: #1f86ff; background-color: #1f86ff;
} }
} }
} */
textarea {
box-sizing: border-box;
width: 100%;
padding: 32rpx;
background: #f2f5fb;
border-radius: 8rpx;
} }
.foot-btn { .foot-btn {
position: fixed; position: fixed;
display: flex; display: flex;
......
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
<wd-icon @click="handleClose" name="close" size="30rpx"></wd-icon> <wd-icon @click="handleClose" name="close" size="30rpx"></wd-icon>
</view> </view>
<wd-picker-view @change="handleConfirm" use-default-slot :columns="columns" v-model="value"></wd-picker-view> <wd-picker-view @change="handleConfirm" use-default-slot :columns="columns" v-model="value"></wd-picker-view>
<view style="width: 100%; display: flex; justify-content: center" <view style="display: flex; justify-content: center; width: 100%"
><wd-button style="width: 80%" @click="handleClose" block :round="false">确定</wd-button></view ><wd-button style="width: 80%" @click="handleClose" block :round="false">确定</wd-button></view
> >
</wd-popup> </wd-popup>
...@@ -283,11 +283,11 @@ initViewData(); ...@@ -283,11 +283,11 @@ initViewData();
border-radius: 50% !important; border-radius: 50% !important;
} }
.title-box { .title-box {
box-sizing: border-box;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
padding: 0 32rpx; padding: 0 32rpx;
box-sizing: border-box;
} }
.welfare { .welfare {
display: flex; display: flex;
...@@ -339,7 +339,6 @@ picker-view { ...@@ -339,7 +339,6 @@ picker-view {
justify-content: space-around; justify-content: space-around;
color: #cccccc; color: #cccccc;
} }
.foot-btn { .foot-btn {
position: fixed; position: fixed;
display: flex; display: flex;
......
...@@ -172,7 +172,6 @@ initViewData(); ...@@ -172,7 +172,6 @@ initViewData();
<style lang="scss" scoped> <style lang="scss" scoped>
@import "./common.scss"; @import "./common.scss";
.foot-btn { .foot-btn {
position: fixed; position: fixed;
display: flex; display: flex;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment