122 lines
3.6 KiB
Vue
122 lines
3.6 KiB
Vue
|
|
<template>
|
||
|
|
<view>
|
||
|
|
<picker mode="selector" :range="displayRange" :disabled="disableChange" @change="onPick">
|
||
|
|
<common-cell :name="name" :required="required">
|
||
|
|
<view class="form-content__wrapper">
|
||
|
|
<view class="flex-main-content truncate" :class="selectLabel ? '' : 'form__placeholder'">
|
||
|
|
{{ selectLabel || placeholder }}
|
||
|
|
</view>
|
||
|
|
<uni-icons class="form-arrow" type="arrowright"></uni-icons>
|
||
|
|
</view>
|
||
|
|
</common-cell>
|
||
|
|
</picker>
|
||
|
|
|
||
|
|
<view v-if="showOther" class="other-row">
|
||
|
|
<input
|
||
|
|
:disabled="disableChange"
|
||
|
|
:value="otherValue"
|
||
|
|
class="other-input"
|
||
|
|
placeholder="请输入补充内容"
|
||
|
|
placeholder-class="form__placeholder"
|
||
|
|
maxlength="50"
|
||
|
|
@input="onOtherInput"
|
||
|
|
/>
|
||
|
|
</view>
|
||
|
|
</view>
|
||
|
|
</template>
|
||
|
|
|
||
|
|
<script setup>
|
||
|
|
import { computed } from 'vue';
|
||
|
|
import commonCell from '../common-cell.vue';
|
||
|
|
|
||
|
|
const emits = defineEmits(['change']);
|
||
|
|
const props = defineProps({
|
||
|
|
form: { type: Object, default: () => ({}) },
|
||
|
|
name: { default: '' },
|
||
|
|
required: { type: Boolean, default: false },
|
||
|
|
title: { default: '' },
|
||
|
|
disableChange: { type: Boolean, default: false },
|
||
|
|
range: { type: Array, default: () => [] },
|
||
|
|
otherFiled: { type: String, default: '其他' },
|
||
|
|
});
|
||
|
|
|
||
|
|
function normalizeOptions(options) {
|
||
|
|
if (!Array.isArray(options)) return [];
|
||
|
|
if (!options.length) return [];
|
||
|
|
if (typeof options[0] === 'string') return options.filter(Boolean).map((i) => ({ label: String(i), value: String(i) }));
|
||
|
|
return options
|
||
|
|
.map((i) => {
|
||
|
|
const label = i?.label ?? i?.name ?? i?.text ?? i?.title ?? '';
|
||
|
|
const value = i?.value ?? i?.id ?? i?.key ?? label;
|
||
|
|
if (!label && (value === undefined || value === null || value === '')) return null;
|
||
|
|
return { label: String(label || value), value: String(value) };
|
||
|
|
})
|
||
|
|
.filter(Boolean);
|
||
|
|
}
|
||
|
|
|
||
|
|
const options = computed(() => normalizeOptions(props.range));
|
||
|
|
const displayRange = computed(() => options.value.map((i) => i.label));
|
||
|
|
const placeholder = computed(() => `请选择${props.name || ''}`);
|
||
|
|
|
||
|
|
const rawValue = computed(() => {
|
||
|
|
const v = props.form?.[props.title];
|
||
|
|
return v === undefined || v === null ? '' : String(v);
|
||
|
|
});
|
||
|
|
|
||
|
|
const isOther = computed(() => {
|
||
|
|
const v = String(rawValue.value || '');
|
||
|
|
if (!v) return false;
|
||
|
|
const known = new Set(options.value.map((i) => String(i.value)));
|
||
|
|
return !known.has(v);
|
||
|
|
});
|
||
|
|
|
||
|
|
const showOther = computed(() => {
|
||
|
|
const selected = selectLabel.value;
|
||
|
|
return selected === props.otherFiled || isOther.value;
|
||
|
|
});
|
||
|
|
|
||
|
|
const selectLabel = computed(() => {
|
||
|
|
const v = String(rawValue.value || '');
|
||
|
|
if (!v) return '';
|
||
|
|
const found = options.value.find((i) => String(i.value) === v);
|
||
|
|
if (found) return found.label;
|
||
|
|
return props.otherFiled;
|
||
|
|
});
|
||
|
|
|
||
|
|
const otherValue = computed(() => (isOther.value ? String(rawValue.value || '') : ''));
|
||
|
|
|
||
|
|
function onPick(e) {
|
||
|
|
const idx = Number(e?.detail?.value || 0);
|
||
|
|
const picked = options.value[idx];
|
||
|
|
if (!picked) return;
|
||
|
|
if (picked.label === props.otherFiled || String(picked.value) === String(props.otherFiled)) {
|
||
|
|
emits('change', { title: props.title, value: '' });
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
emits('change', { title: props.title, value: picked.value });
|
||
|
|
}
|
||
|
|
|
||
|
|
function onOtherInput(e) {
|
||
|
|
emits('change', { title: props.title, value: String(e?.detail?.value || '') });
|
||
|
|
}
|
||
|
|
</script>
|
||
|
|
|
||
|
|
<style lang="scss" scoped>
|
||
|
|
@import '../cell-style.css';
|
||
|
|
|
||
|
|
.other-row {
|
||
|
|
padding: 0 30rpx 24rpx;
|
||
|
|
border-bottom: 1px solid #eee;
|
||
|
|
background: #fff;
|
||
|
|
}
|
||
|
|
|
||
|
|
.other-input {
|
||
|
|
width: 100%;
|
||
|
|
font-size: 28rpx;
|
||
|
|
padding: 18rpx 20rpx;
|
||
|
|
border: 1px solid #eee;
|
||
|
|
border-radius: 8rpx;
|
||
|
|
box-sizing: border-box;
|
||
|
|
}
|
||
|
|
</style>
|