| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522 |
- <template>
- <view class="form-group" :ref="setItemRef">
- <view v-if="label" class="form-label"><text class="required-mark">{{ required ? "*" : "" }}</text> {{ label }}
- </view>
- <u-form-item :prop="rulesKey">
- <template v-if="type === 'text' || type === 'password'">
- <up-input v-model="inputValueDoc" class="form-input" :type="type"
- :placeholder="placeholder ? placeholder : t('common.input')" :readonly="readonly" :disabled="disabled"
- :clearable="clearable" :maxlength="maxlength" :errorMessage="errorMessage" @blur="handleBlur"
- @focus="handleFocus" @clear="handleClear">
- <template #prefix>
- <slot name="left-icon1"></slot>
- </template>
- <template #suffix>
- <slot name="right-icon1"></slot>
- </template>
- </up-input>
- </template>
- <template v-if="type === 'number'">
- <up-input v-model="inputValueDoc" class="form-input" type="number"
- :placeholder="placeholder ? placeholder : t('common.input')" :readonly="readonly" :disabled="disabled"
- :clearable="clearable" :maxlength="maxlength" :errorMessage="errorMessage" @blur="handleBlur"
- @focus="handleFocus" @clear="handleClear">
- <slot></slot>
- </up-input>
- </template>
- <template v-if="type === 'dropdown'">
- <view class="input-wrapper" @click.stop="handleInputClick">
- <view class="input-bg"></view>
- <up-input v-model="inputValueDoc" class="form-input"
- :placeholder="placeholder ? placeholder : t('common.choose')" :readonly="true" :disabled="disabled"
- :clearable="clearable" :errorMessage="errorMessage" @clear="handleClear">
- <template #suffix>
- <up-icon name="arrow-down" size="14"></up-icon>
- </template>
- <slot></slot>
- </up-input>
- </view>
- <up-action-sheet :show="filteredColumns.length && showPicker" :actions="filteredColumns"
- @select="onActionSheetConfirm" @close="showPicker = false" />
- </template>
- <template v-if="type === 'select'">
- <view class="input-wrapper" @click.stop="handleInputClick">
- <view class="input-bg"></view>
- <up-input v-model="inputValueDoc" class="form-input"
- :placeholder="placeholder ? placeholder : t('common.choose')" :readonly="true" :disabled="disabled"
- :clearable="clearable" :errorMessage="errorMessage" @clear="handleClear">
- <template #suffix>
- <up-icon name="arrow-down" size="14"></up-icon>
- </template>
- <slot></slot>
- </up-input>
- </view>
- <!-- :showSearch="false" :options="selectPopup.options" v-model="selectPopup.show" @select="onSelectConfirm" -->
- <cwg-more-select v-if="showPicker" :showSearch="showSearch" :input-value="inputValueDoc"
- :options="filteredColumns" v-model="showPicker" @select="onConfirm" />
- </template>
- <template v-if="type === 'date'">
- <view class="input-wrapper" @click="handleInputClick">
- <view class="input-bg"></view>
- <up-input v-model="inputValueDoc" class="form-input"
- :placeholder="placeholder ? placeholder : t('common.choose')" :readonly="true" :disabled="disabled"
- :clearable="clearable" :errorMessage="errorMessage" @clear="handleClear">
- <template #suffix>
- <up-icon name="calendar" size="14"></up-icon>
- </template>
- </up-input>
- </view>
- <cwg-date-picker v-model:show="showPicker" v-model="inputValueDoc" mode="date" @confirm="onDateConfirm"
- :minDate="minDate" :maxDate="maxDate" />
- </template>
- <template v-if="type === 'upload'">
- <view class="form-input uploader">
- <up-upload v-if="!isUploadD" :fileList="uploader" :disabled="disabled" :deletable="!disabled" :accept="accept"
- :maxCount="1" @afterRead="afterRead" @delete="handleDelete"></up-upload>
- <up-upload v-if="isUploadD" :fileList="uploader" :disabled="disabled" :deletable="!disabled" :maxCount="1"
- @afterRead="afterRead" @delete="handleDelete">
- <slot></slot>
- </up-upload>
- </view>
- </template>
- </u-form-item>
- </view>
- </template>
- <script setup>
- import { ref, onMounted, watch, computed, defineProps } from "vue";
- import dayjs from "dayjs";
- import { upload } from "@/utils/request";
- import { uploadApi } from "@/api/upload";
- import config from "@/config";
- import { useI18n } from "vue-i18n";
- const { t } = useI18n();
- const props = defineProps({
- type: {
- type: String,
- default: "text",
- validator: (v) =>
- [
- "text",
- "password",
- "number",
- "select",
- "date",
- "dropdown",
- "upload",
- ].includes(v),
- },
- label: String,
- fkey: String,
- rulesKey: String,
- accept: String,
- showSearch: Boolean,
- isUploadD: { type: Boolean, default: false },
- value: { type: [String, Number] },
- selectedValueDoc: { type: [String, Number] },
- placeholder: String,
- direction: { type: String, default: "down" },
- disabled: Boolean,
- readonly: Boolean,
- required: Boolean,
- max: Number,
- clearable: { type: Boolean, default: true },
- columns: { type: Array, default: () => [] },
- rules: { type: Array, default: () => [] },
- maxlength: Number,
- errorMessage: String,
- minDate: { type: Date, default: () => new Date(1920, 0, 1).getTime() },
- maxDate: { type: Date, default: () => new Date().getTime() },
- dateFormatter: { type: Function, default: (_type, val) => val },
- displayFormatter: {
- type: Function,
- default: (val) => dayjs(val).format("YYYY-MM-DD"),
- },
- });
- // console.log(props, 'props');
- const itemRef = ref(null)
- const setItemRef = el => {
- if (el) itemRef.value = el
- }
- const emit = defineEmits([
- "update:value",
- "blur",
- "focus",
- "clear",
- "confirm",
- "change",
- "change1",
- ]);
- const isUploading = ref(false);
- const uploader = ref([]);
- const inputValueDoc = ref("");
- const selectedValueDoc = ref([]);
- const showPicker = ref(false);
- const onConfirm = (value) => {
- let selectedText = value.text || ''
- if (props.fkey == 'areaCode') {
- selectedText = selectedText
- }
- inputValueDoc.value = selectedText
- showPicker.value = false
- emit("update:selectedValueDoc", selectedText);
- }
- // 处理输入框点击事件
- function handleInputClick() {
- if (props.disabled || props.readonly) return;
- showPicker.value = true;
- }
- function absoluteUrl(url) {
- if (!url) {
- return "";
- }
- if (/^https?:\/\//.test(url)) {
- return url;
- }
- const prefix = config.Host85 || "";
- if (!prefix) {
- return url;
- }
- return `${prefix}${url.startsWith("/") ? url : `/${url}`}`;
- }
- async function afterRead(file) {
- isUploading.value = true;
- uni.showLoading({
- title: "上传中...",
- mask: true,
- });
- try {
- // console.log(file.file, file);
- const result = await uploadApi.uploadFile(file.file);
- // console.log(500, result);
- uni.hideLoading();
- if (result.code === 200) {
- inputValueDoc.value = result.data;
- uploader.value = [{ url: absoluteUrl(result.data) }];
- uni.showToast({
- title: "上传成功",
- icon: "success",
- });
- setTimeout(() => {
- isUploading.value = false;
- }, 100);
- } else {
- uni.showToast({
- title: result.message || "上传失败",
- icon: "none",
- });
- isUploading.value = false;
- inputValueDoc.value = "";
- uploader.value = [];
- }
- } catch (_error) {
- uni.hideLoading();
- uni.showToast({
- title: _error.message || "上传失败",
- icon: "none",
- });
- }
- }
- async function afterRead1(event) {
- // console.log(event, 198);
- isUploading.value = true;
- uni.showLoading({
- title: "上传中...",
- mask: true,
- });
- try {
- // uview-plus 的 upload 组件返回的是 { file, fileList }
- // file 对象包含 url(临时路径)或 path 属性
- const file = event.file || (Array.isArray(event) ? event[0] : event);
- const filePath = file.url || file.path || file.tempFilePath;
- if (!filePath) {
- throw new Error("文件路径不存在");
- }
- // 使用 uni-app 的 upload 方法,需要传入 filePath
- const result = await upload({
- url: "/wasabi/api/upload/file",
- filePath: filePath,
- });
- uni.hideLoading();
- // console.log(500, result);
- if (result.code === 200) {
- inputValueDoc.value = result.data;
- uploader.value = [{ url: absoluteUrl(result.data) }];
- uni.showToast({
- title: "上传成功",
- icon: "success",
- });
- setTimeout(() => {
- isUploading.value = false;
- }, 100);
- } else {
- uni.showToast({
- title: result.message || "上传失败",
- icon: "none",
- });
- isUploading.value = false;
- inputValueDoc.value = "";
- uploader.value = [];
- }
- } catch (_error) {
- uni.hideLoading();
- uni.showToast({
- title: _error.message || "上传失败",
- icon: "none",
- });
- isUploading.value = false;
- uploader.value = [];
- }
- }
- function handleDelete(event) {
- const index = event.index;
- uploader.value.splice(index, 1);
- inputValueDoc.value = "";
- emit("update:value", "");
- emit("change", { value: "", key: props.fkey });
- }
- const filteredColumns = computed(() => {
- if (props.type === "dropdown") {
- return props.columns.map((item) => {
- return { ...item, name: item.text };
- });
- }
- return props.columns;
- });
- watch(
- () => inputValueDoc.value,
- (newVal) => {
- // if (!newVal) return
- if (
- props.type === "text" ||
- props.type === "number" ||
- props.type === "password"
- ) {
- emit("update:value", newVal);
- emit("change", { value: newVal, key: props.fkey });
- } else if (props.type === "select") {
- const matched = props.columns.find((opt) => opt.text === newVal);
- emit("update:value", matched?.value || "");
- emit("change", { value: matched?.value || "", key: props.fkey });
- } else if (props.type === "date") {
- emit("update:value", newVal);
- emit("change", { value: newVal, key: props.fkey });
- } else if (props.type === "upload") {
- emit("update:value", newVal);
- emit("change", { value: newVal, key: props.fkey });
- } else if (props.type === "dropdown") {
- const matched = props.columns.find((opt) => opt.text === newVal);
- emit("update:value", matched?.value || "");
- emit("change", { value: matched?.value || "", key: props.fkey });
- }
- }
- );
- watch(
- () => props.value,
- (newVal) => {
- if (isUploading.value) return;
- if (props.type === "date") {
- inputValueDoc.value = newVal ? dayjs(newVal).format("YYYY-MM-DD") : "";
- } else if (props.type === "select") {
- const matched = props.columns.find((opt) => opt.value === newVal);
- inputValueDoc.value = matched?.text || "";
- selectedValueDoc.value = matched ? [matched.value] : [];
- } else if (props.type === "upload") {
- uploader.value = props.value
- ? [{ url: absoluteUrl(String(props.value)) }]
- : [];
- // console.log(uploader.value, 198);
- inputValueDoc.value = props.value || "";
- } else if (props.type === "dropdown") {
- const matched = props.columns.find((opt) => opt.value === newVal);
- inputValueDoc.value = matched?.text || "";
- selectedValueDoc.value = matched ? [matched.value] : [];
- } else {
- inputValueDoc.value = newVal || "";
- }
- },
- { immediate: true }
- );
- function handleBlur(event) {
- emit("blur", event);
- }
- function handleFocus(event) {
- emit("focus", event);
- }
- function handleClear() {
- inputValueDoc.value = "";
- emit("update:value", "");
- emit("clear");
- }
- function onActionSheetConfirm(value) {
- const selectedText = value.text || value.name || "";
- inputValueDoc.value = selectedText;
- showPicker.value = false;
- const matched = props.columns.find(
- (opt) => opt.text === selectedText || opt.name === selectedText
- );
- emit("update:value", matched?.value || "");
- emit("change", { value: matched?.value || "", key: props.fkey });
- }
- function onPickerConfirm(event) {
- const { value } = event;
- const selectedItem =
- Array.isArray(value) && value.length > 0 ? value[0] : value;
- const matched = props.columns.find(
- (opt) => opt.value === selectedItem || opt.value === selectedItem?.value
- );
- if (matched) {
- inputValueDoc.value = matched.text;
- emit("update:value", matched.value);
- emit("change", { value: matched.value, key: props.fkey });
- }
- showPicker.value = false;
- }
- function onDateConfirm(event) {
- const { formatted } = event;
- inputValueDoc.value = formatted;
- showPicker.value = false;
- emit("update:value", formatted);
- emit("change", { value: formatted, key: props.fkey });
- }
- </script>
- <style scoped lang="scss">
- @import "@/uni.scss";
- .form-group {
- width: 100%;
- margin-bottom: px2rpx(12);
- transform: none;
- }
- .form-label {
- font-size: var(--font-size-16);
- line-height: px2rpx(24);
- letter-spacing: px2rpx(1);
- color: #474747;
- margin: px2rpx(16) 0 px2rpx(8) 0;
- display: flex;
- align-self: start;
- .required-mark {
- color: red;
- }
- }
- .form-input {
- width: 100%;
- border: 1px solid var(--border) !important;
- border-radius: 10px !important;
- font-size: px2rpx(31) !important;
- margin-top: px2rpx(4) !important;
- padding: px2rpx(10) px2rpx(12) !important;
- box-sizing: border-box;
- }
- .search-field {
- background: var(--black);
- border: none !important;
- padding-left: px2rpx(10) !important;
- }
- .uploader {
- border: none !important;
- background: transparent !important;
- padding-left: 0;
- padding-right: 0;
- width: 100%;
- }
- .input-wrapper {
- position: relative;
- width: 100%;
- .input-bg {
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- z-index: 100;
- }
- }
- // uview-plus 组件样式覆盖
- :deep(.u-input) {
- border-radius: 10px !important;
- font-size: px2rpx(31) !important;
- padding: px2rpx(12);
- background: transparent;
- color: var(--white);
- &::after {
- border: none !important;
- }
- }
- :deep(.up-input__content__field-wrapper__field) {
- color: var(--white);
- line-height: px2rpx(22);
- &::placeholder {
- color: var(--lable) !important;
- }
- }
- :deep(.up-icon) {
- color: var(--black1) !important;
- }
- :deep(.u-form-item__body__right__message) {
- position: relative;
- top: px2rpx(4);
- }
- :deep(.u-upload__wrap) {
- width: 100%;
- >view {
- width: 100% !important;
- }
- .u-upload__wrap__preview__image {
- width: 100% !important;
- height: px2rpx(160) !important;
- border-radius: px2rpx(4);
- }
- .u-upload__deletable {
- width: px2rpx(24) !important;
- height: px2rpx(24) !important;
- background-color: rgba(0, 0, 0, 0.6) !important;
- }
- .u-icon__icon {
- width: px2rpx(18) !important;
- height: px2rpx(18) !important;
- font-size: px2rpx(18) !important;
- }
- }
- </style>
|