Explorar el Código

🎨 优化细节

快乐的梦鱼 hace 3 semanas
padre
commit
340e6a4850

+ 8 - 0
src/components/form/CascadePicker.vue

@@ -62,6 +62,7 @@ const props = withDefaults(defineProps<CascadePickerProps>(), {
 
 const pickerVisibleCols = ref<CascadePickerItem[][]>([]);
 const pickerSelectIndex = ref<number[]>([]);
+const currentText = ref<string>('');
 
 function bindChange(e: any) {
   const val = e.detail.value as number[];
@@ -94,6 +95,7 @@ function bindChange(e: any) {
 
   emit('update:value', resultValue);
   emit('selectTextChange', selectText.join(' '));
+  currentText.value = selectText.join(' ');
 }
 function loadCols() {
   const selectText : string[] = [];
@@ -111,6 +113,7 @@ function loadCols() {
     } 
   }
   emit('selectTextChange', selectText.join(' '), true);
+  currentText.value = selectText.join(' ');
 }
 
 watch(() => props.value, (v) => {
@@ -120,6 +123,11 @@ onMounted(() => {
   loadCols();
 })
 
+defineExpose({
+  getSelectedText: () => {
+    return currentText.value;
+  },
+});
 defineOptions({
   options: {
     styleIsolation: "shared",

+ 8 - 4
src/components/form/CascadePickerField.vue

@@ -13,9 +13,9 @@
       @confirm="onConfirm"
     />
     <CascadePicker 
+      ref="pickerRef"
       v-bind="props"
-      v-model:value="tempValue" 
-      @selectTextChange="onSelectTextChange"
+      v-model:value="tempValue"
     />
   </Popup>
   <Text
@@ -90,7 +90,7 @@ const props = withDefaults(defineProps<CascadePickerFieldProps>(), {
 });
 
 const popupShow = ref(false);
-
+const pickerRef = ref();
 const {
   value,
   updateValue,
@@ -105,7 +105,6 @@ const {
 );
 
 const {
-  onSelectTextChange,
   onCancel,
   onConfirm,
   selectText,
@@ -117,6 +116,11 @@ const {
   emit as any,
   [],
   props.shouldUpdateValueImmediately,
+  (v) => {
+    if (!v || v.length === 0)
+      return '';
+    return pickerRef.value?.getSelectedText() ?? '';
+  },
   undefined,
   popupShow,
 );

+ 6 - 14
src/components/form/CascaderField.vue

@@ -16,7 +16,6 @@
       v-bind="props"
       :modelValue="tempValue"
       @update:modelValue="(v:any) => tempValue = v"
-      @selectTextChange="onSelectTextChange"
       @pickEnd="onPickEnd"
     />
     <slot name="footer">
@@ -35,7 +34,7 @@
 </template>
 
 <script setup lang="ts">
-import { ref, toRef, watch } from 'vue';
+import { ref, toRef } from 'vue';
 import { useFieldChildValueInjector } from './FormContext';
 import { usePickerFieldTempStorageData } from './PickerUtils';
 import type { CascaderProps } from './Cascader.vue';
@@ -124,7 +123,6 @@ const {
 );
 
 const {
-  onSelectTextChange,
   onCancel,
   onConfirm,
   selectText,
@@ -136,6 +134,11 @@ const {
   emit as any,
   [],
   props.shouldUpdateValueImmediately,
+  (v) => {
+    if (!v || v.length === 0)
+      return '';
+    return getCascaderText(v, props.valueKey, props.textKey, props.childrenKey, props.data);
+  },
   props.beforeConfirm,
   popupShow,
 );
@@ -145,17 +148,6 @@ function onPickEnd() {
     onConfirm();
 }
 
-watch(tempValue, (v) => {
-  if (!popupShow.value)
-    onSelectTextChange(getCascaderText(
-      v, 
-      props.valueKey, 
-      props.textKey, 
-      props.childrenKey, 
-      props.data
-    ), true);
-}, { immediate: true })
-
 defineExpose({
   confirm: onConfirm,
   cancel: onCancel,

+ 5 - 2
src/components/form/DatePicker.vue

@@ -110,6 +110,8 @@ const columns = computed(() => {
   return cols;
 });
 
+let forceUpdate = true;
+
 // 更新选中的值
 function updateValue(v: number[]) {
   if (props.modelValue || v.length > 0) {
@@ -130,10 +132,11 @@ function updateValue(v: number[]) {
       }
       emit('update:modelValue', date);
     }
-    emit('selectTextChange', DateUtils.formatDate(date, 'yyyy-MM-dd'));
+    emit('selectTextChange', DateUtils.formatDate(date, 'yyyy-MM-dd'), forceUpdate);
   } else {
-    emit('selectTextChange', '');
+    emit('selectTextChange', '', forceUpdate);
   }
+  forceUpdate = false;
 }
 onMounted(() => updateValue([]));
 

+ 3 - 2
src/components/form/DatePickerField.vue

@@ -15,7 +15,6 @@
     <DatePicker 
       v-bind="props"
       v-model="tempValue"
-      @selectTextChange="onSelectTextChange"
     />
   </Popup>
   <Text
@@ -38,6 +37,7 @@ import DatePicker from './DatePicker.vue';
 import { usePickerFieldTempStorageData } from './PickerUtils';
 import Text, { type TextProps } from '../basic/Text.vue';
 import { usePickerFieldInstance, type PickerFieldInstance } from './Picker';
+import { DateUtils } from '@imengyu/imengyu-utils';
 
 export interface DatePickerFieldProps extends Omit<DatePickerProps, 'modelValue'> {
   modelValue?: Date;
@@ -105,7 +105,6 @@ const {
 );
 
 const {
-  onSelectTextChange,
   onCancel,
   onConfirm,
   selectText,
@@ -117,10 +116,12 @@ const {
   emit as any,
   new Date(),
   props.shouldUpdateValueImmediately,
+  (v) => DateUtils.formatDate(v, 'yyyy-MM-dd'),
   undefined,
   popupShow,
 );
 
+
 defineExpose<PickerFieldInstance>(usePickerFieldInstance(popupShow));
 defineOptions({
   options: {

+ 5 - 2
src/components/form/DateTimePicker.vue

@@ -167,6 +167,8 @@ const columns = computed(() => {
   return cols;
 });
 
+let forceUpdate = true;
+
 // 更新选中的值
 function updateValue(v: number[]) {
   if (props.modelValue || v.length > 0) {
@@ -198,10 +200,11 @@ function updateValue(v: number[]) {
       }
       emit('update:modelValue', date);
     }
-    emit('selectTextChange', DateUtils.formatDate(date, 'yyyy-MM-dd HH:mm:ss')); 
+    emit('selectTextChange', DateUtils.formatDate(date, 'yyyy-MM-dd'), forceUpdate);
   } else {
-    emit('selectTextChange', '');
+    emit('selectTextChange', '', forceUpdate);
   }
+  forceUpdate = false;
 }
 onMounted(() => updateValue([]));
 

+ 2 - 2
src/components/form/DateTimePickerField.vue

@@ -15,7 +15,6 @@
     <DateTimePicker 
       v-bind="props"
       v-model="tempValue"
-      @selectTextChange="onSelectTextChange"
     />
   </Popup>
   <Text
@@ -38,6 +37,7 @@ import DateTimePicker from './DateTimePicker.vue';
 import { usePickerFieldTempStorageData } from './PickerUtils';
 import Text, { type TextProps } from '../basic/Text.vue';
 import { usePickerFieldInstance, type PickerFieldInstance } from './Picker';
+import { DateUtils } from '@imengyu/imengyu-utils';
 
 export interface DateTimePickerFieldProps extends Omit<DateTimePickerProps, 'modelValue'> {
   modelValue?: Date;
@@ -108,7 +108,6 @@ const {
 );
 
 const {
-  onSelectTextChange,
   onCancel,
   onConfirm,
   selectText,
@@ -120,6 +119,7 @@ const {
   emit as any,
   new Date(),
   props.shouldUpdateValueImmediately,
+  (v) => DateUtils.formatDate(v, 'yyyy-MM-dd HH:mm:ss'),
   undefined,
   popupShow,
 );

+ 12 - 0
src/components/form/Picker.vue

@@ -59,6 +59,7 @@ const emit = defineEmits([ 'update:value', 'selectTextChange' ]);
 const props = withDefaults(defineProps<PickerProps>(), {
   pickerHeight: 300,
   pickerWidth: 750,
+  columns: () => [],
 });
 
 const loaded = ref(false);
@@ -117,6 +118,17 @@ onMounted(() => {
 const themeStyles = themeContext.useThemeStyles({
 });
 
+defineExpose({
+  refresh: loadValues,
+  getSelectedText: () => {
+    return pickerSelectIndex.value.map((p, i) => {
+      const cols = props.columns[i];
+      if (!cols || cols.length === 0) 
+        return null;
+      return cols[p]?.text ?? cols[0]?.text ?? null;
+    }).join(' ');
+  },
+});
 defineOptions({
   options: {
     styleIsolation: "shared",

+ 7 - 2
src/components/form/PickerField.vue

@@ -13,9 +13,9 @@
       @confirm="onConfirm"
     />
     <Picker 
+      ref="pickerRef"
       v-bind="props"
       v-model:value="tempValue"
-      @selectTextChange="onSelectTextChange"
     />
   </Popup>
   <Text
@@ -93,6 +93,7 @@ const props = withDefaults(defineProps<PickerFieldProps>(), {
 });
 
 const popupShow = ref(false);
+const pickerRef = ref();
 
 const {
   value,
@@ -108,7 +109,6 @@ const {
 );
 
 const {
-  onSelectTextChange,
   onCancel,
   onConfirm,
   selectText,
@@ -120,6 +120,11 @@ const {
   emit as any,
   [],
   props.shouldUpdateValueImmediately,
+  (v) => {
+    if (!v || v.length === 0)
+      return '';
+    return pickerRef.value?.getSelectedText() ?? '';
+  },
   undefined,
   popupShow,
 );

+ 28 - 36
src/components/form/PickerUtils.ts

@@ -1,18 +1,18 @@
-import { nextTick, ref, watch, type Ref } from "vue";
+import { onMounted, ref, watch, type Ref } from "vue";
 
 /**
  * 选择器字段临时存储数据的组合式函数
  * 用于管理选择器组件的临时值、选择文本和交互逻辑
  * 
  * @template T - 值的类型
- * @param 当前值的响应式引用
- * @param 更新值的回调函数
- * @param 关闭弹窗的回调函数
- * @param 事件发射器函数
- * @param 默认的新值
- * @param 是否立即更新值
- * @param 确认前的回调函数,返回true时取消确认
- * @param 弹窗显示状态的响应式引用
+ * @param value - 当前值的响应式引用
+ * @param updateValue - 更新值的回调函数
+ * @param closePopup - 关闭弹窗的回调函数
+ * @param emit - 事件发射器函数
+ * @param defaultNewValue - 默认的新值
+ * @param shouldUpdateValueImmediately - 是否立即更新值至绑定值
+ * @param beforeConfirm - 确认前的回调函数,返回true时取消确认
+ * @param popupShow - 弹窗显示状态的响应式引用
  */
 export function usePickerFieldTempStorageData<T>(
   value: Ref<T>, 
@@ -21,36 +21,25 @@ export function usePickerFieldTempStorageData<T>(
   emit: (name: string, d?: any) => void,
   defaultNewValue: T,
   shouldUpdateValueImmediately: boolean,
+  requireFormat: (value: T) => string,
   beforeConfirm?: ((value: T) => Promise<boolean>) | undefined,
   popupShow?: Ref<boolean>,
 ) {
 
-  let tempSelectText = '';
-  let tempLastSelectText = '';
   // 临时值的响应式引用,初始值为当前值或默认新值
   const tempValue = ref(value.value ?? defaultNewValue) as Ref<T>;
+  const beforeConfirmValue = ref(value.value ?? defaultNewValue) as Ref<T>;
   // 显示的文本的响应式引用
   const selectText = ref('');
 
   /**
-   * 当选择文本变化时的处理函数
-   * @param 新的选择文本
-   * @param 是否强制更新显示的选择文本
-   */
-  function onSelectTextChange(t: string, forceUpdate = false) {
-    tempSelectText = t;
-    emit('selectTextChange', t);
-    if (forceUpdate)
-      selectText.value = t;
-  }
-
-  /**
-   * 取消选择的处理函数
+   * 取消选择。恢复临时值为当前值或默认新值
    */
   function onCancel() {
     closePopup();
+    tempValue.value = beforeConfirmValue.value;
+    updateValue(tempValue.value);
     emit('cancel');
-    selectText.value = tempLastSelectText;
   }
 
   /**
@@ -61,13 +50,13 @@ export function usePickerFieldTempStorageData<T>(
     // 如果有确认前回调且返回true,则取消确认
     if (beforeConfirm && await beforeConfirm(tempValue.value))
       return;
-    selectText.value = tempSelectText;
     updateValue(tempValue.value);
     emit('confirm', value.value);
   }
 
   watch(value, (v) => {
     tempValue.value = v;
+    selectText.value = requireFormat(v);
   });
   watch(tempValue, (v) => {
     emit('tempValueChange', tempValue.value);
@@ -79,19 +68,22 @@ export function usePickerFieldTempStorageData<T>(
   if (popupShow) {
     watch(popupShow, (v) => {
       if (v) {
-        // 弹窗显示时,记录当前的选择文本作为上一次的选择文本
-        nextTick(() => {
-          tempLastSelectText = tempSelectText;
-        });
+        beforeConfirmValue.value = tempValue.value;
       }
-    })
+    });
   }
 
+  onMounted(() => {
+    if (value.value)
+      selectText.value = requireFormat(value.value);
+    else
+      selectText.value = '';
+  });
+
   return {
-    onSelectTextChange, // 选择文本变化处理函数
-    onCancel, // 取消处理函数
-    onConfirm, // 确认处理函数
-    selectText, // 显示的选择文本
-    tempValue, // 临时值
+    onCancel,
+    onConfirm,
+    selectText,
+    tempValue,
   }
 }

+ 18 - 3
src/components/form/TimePickerField.vue

@@ -15,7 +15,6 @@
     <TimePicker 
       v-bind="props"
       v-model="tempValue"
-      @selectTextChange="onSelectTextChange"
     />
   </Popup>
   <Text
@@ -29,7 +28,7 @@
 </template>
 
 <script setup lang="ts">
-import { ref, toRef } from 'vue';
+import { computed, ref, toRef } from 'vue';
 import { useFieldChildValueInjector } from './FormContext';
 import type { TimePickerProps } from './TimePicker.vue';
 import Popup from '../dialog/Popup.vue';
@@ -38,6 +37,7 @@ import TimePicker from './TimePicker.vue';
 import { usePickerFieldTempStorageData } from './PickerUtils';
 import Text, { type TextProps } from '../basic/Text.vue';
 import { usePickerFieldInstance, type PickerFieldInstance } from './Picker';
+import { DateUtils } from '@imengyu/imengyu-utils';
 
 export interface TimePickerFieldProps extends Omit<TimePickerProps, 'modelValue'> {
   modelValue?: Date;
@@ -100,8 +100,18 @@ const {
   props.initalValue,
 );
 
+const format = computed(() => {
+  const formats = []
+  if (props.showHours)
+    formats.push('HH');
+  if (props.showMinute)
+    formats.push('mm');
+  if (props.showSecond)
+    formats.push('ss');
+  return formats.join(':');
+});
+
 const {
-  onSelectTextChange,
   onCancel,
   onConfirm,
   selectText,
@@ -113,6 +123,11 @@ const {
   emit as any,
   new Date(),
   props.shouldUpdateValueImmediately,
+  (v) => {
+    if (!v)
+      return '';
+    return DateUtils.formatDate(v, format.value);
+  },
   undefined,
   popupShow,
 );