Преглед изворни кода

🎨 优化采集提交细节问题

快乐的梦鱼 пре 3 дана
родитељ
комит
f3c9d4430d

+ 21 - 10
src/api/inhert/VillageInfoApi.ts

@@ -23,17 +23,18 @@ export class CategoryListItem extends DataModel<CategoryListItem> {
   children?: CategoryListItem[];
 }
 export class CommonInfoModel extends DataModel<CommonInfoModel> {
-  constructor() {
-    super(CommonInfoModel, "信息详情");
+  constructor(name?: string) {
+    super(CommonInfoModel, name ?? "信息详情");
     this.setNameMapperCase('Camel', 'Snake');
     this._convertTable = {
       id: { clientSide: 'number', serverSide: 'number', clientSideRequired: true },
       keywords: { clientSide: 'splitCommaArray', serverSide: 'commaArrayMerge' },
       culturalType: { clientSide: 'number', serverSide: 'number' },
       productType: { clientSide: 'number', serverSide: 'number' },
+      folkCultureType: { clientSide: 'number', serverSide: 'number' },
       type: { clientSide: 'number', serverSide: 'number' },
+      status: { clientSide: 'number', serverSide: 'number' },
       nature: { clientSide: 'number', serverSide: 'number' },
-      folkCultureType: { clientSide: 'number', serverSide: 'number' },
       landforms: [
         { clientSide: 'splitCommaArray', serverSide: 'commaArrayMerge' },
         { clientSide: 'arrayInt', serverSide: 'original' },
@@ -193,11 +194,12 @@ export class VillageListItem extends DataModel<VillageListItem> {
   desc = '';
   image = '';
 }
-export class VillageBulidingInfo extends DataModel<VillageBulidingInfo> {
+export class VillageBulidingInfo extends CommonInfoModel {
   constructor() {
-    super(VillageBulidingInfo, "历史建筑信息");
+    super("历史建筑信息");
     this.setNameMapperCase('Camel', 'Snake');
     this._convertTable = {
+      ...this._convertTable,
       id: { clientSide: 'number', serverSide: 'number', clientSideRequired: true },
     }
     this._blackList.toServer.push(
@@ -212,10 +214,14 @@ export class VillageBulidingInfo extends DataModel<VillageBulidingInfo> {
           { clientSide: 'splitCommaArray', serverSide: 'commaArrayMerge' },
           { clientSide: 'arrayInt', serverSide: 'original' },
         ];
+      if (key.endsWith('At'))
+        return {
+          clientSide: 'date',
+          serverSide: 'string',
+        };
       return undefined;
     };
   }
-  id !: number;
 }
 
 export class VillageInfoApi extends AppServerRequestModule<DataModel> {
@@ -255,10 +261,12 @@ export class VillageInfoApi extends AppServerRequestModule<DataModel> {
     id?: number, 
     modelClassCreator: (new () => T) = CommonInfoModel as any
   ) {
-    return (await this.post(`/village/collect/info`, '通用获取信息详情', {
-      collect_module_id: collectModuleId,
-      id,
-    }, undefined, modelClassCreator)).data as T
+    return new modelClassCreator().fromServerSide(
+      (await this.post<KeyValue>(`/village/collect/info`, '通用获取信息详情', {
+        collect_module_id: collectModuleId,
+        id,
+      })).requireData()
+    );
   }
   async getList<T extends DataModel = CommonInfoModel>(data: {
     collectModuleId?: number|undefined,
@@ -354,6 +362,9 @@ export class VillageInfoApi extends AppServerRequestModule<DataModel> {
     };
     if (subKey && subId && subId > 0)
       res[subKey] = subId;
+    if (Array.isArray(res.type))
+      debugger;
+
     return (await this.post(`/village/collect/save`, '通用更新信息详情', res));
   }
   async getInfoByVillageId(id: number) {

+ 21 - 4
src/api/light/LightVillageApi.ts

@@ -258,8 +258,13 @@ export class VillageListItem extends DataModel<VillageListItem> {
   imageLimit = 0;
   /** 存储内存限制(MB) */
   storageLimit = 0;
+  /** 存储内存已使用(MB) */
+  storageUsed = 0;
   /** 可设置管理人员数量 */
   managerLimit = 0;
+
+  /** 志愿者在村落昵称 */
+  villageNickname = '';
 }
 
 export interface VillageTreeAnimProps {
@@ -406,15 +411,27 @@ export class LightVillageApi extends AppServerRequestModule<DataModel> {
     area_code: number,
     /**
      * 村落类型:
-      95=自然村
-      96=行政村,
-      334=社区
+       95=自然村
+       96=行政村,
+       334=社区
      */
     village_type: number,
   }) {
     return await this.post<KeyValue>('/village/village/addVillage', '创建村社', data);
   }
-  
+
+  async updateStorage(params: {
+    /** 村社ID */
+    villageId: number;
+    /** 文件大小(字节) */
+    memorySize: number;
+  }) {
+    return await this.post<KeyValue>('/village/village/updateStorage', '更新存储', {
+      village_id: params.villageId,
+      memory_size: params.memorySize,
+    });
+  }
+
 }
 
 

+ 1 - 1
src/common/components/form/RichTextEditor.vue

@@ -1,7 +1,7 @@
 <template>
   <FlexCol>
     <view class="richtext-preview-box" @click="() => !disabled && !readonly ? edit() : preview()">
-      <Parse v-if="modelValue" :content="modelValue" containerStyle="max-height:400px" />
+      <Parse v-if="modelValue" :content="modelValue" containerStyle="max-height:400px;word-break:break-all;" />
       <Text v-else color="text.second">{{placeholder}}</Text>
       <view v-if="modelValue" class="richtext-preview-mask" :style="maskStyle" />
     </view>

+ 12 - 0
src/components/dynamic/DynamicForm.ts

@@ -249,6 +249,11 @@ export interface IDynamicFormRef {
    */
   getFormItemControlRef: <T>(key: string) => T;
   /**
+   * 获取通过 props.globalParams 传入的全局参数
+   * @returns 
+   */
+  getGlobalParams: () => IDynamicFormObject;
+  /**
    * 获取指定类型的所有表单项组件的 Ref
    * @param type 组件类型
    * @returns 
@@ -291,6 +296,13 @@ export interface IDynamicFormRef {
    */
   dispatchReload: () => void;
   /**
+   * 向顶层表单组件发送消息事件。
+   * @param messageName 消息名称。  
+   * @param data 可选参数。
+   * @returns 
+   */
+  emitMessage: (messageName: string, ...data: unknown[]) => void;
+  /**
    * 获取当前表单中可见的所有字段名
    */
   getVisibleFormNames: () => string[];

+ 35 - 4
src/components/dynamic/DynamicForm.vue

@@ -149,7 +149,33 @@ function dispatchReload() {
   dispatchMessage(MESSAGE_RELOAD);
 }
 
-//初始化默认值到模型
+/**
+ * 初始化默认值到模型
+ * 
+ * currentKey 递归规则
+ * * flat-simple/flat-group 忽略本级key继承父级:
+ *    例如: 以下结构应推断路径为 user.district
+        object (name: "user")
+          └─ flat-simple (name: "group1")
+            └─ flat-simple (name: "group2")
+              └─ dropdown1 (name: "district", defaultValue: "Beijing")
+ * * object/object-group 父级key.子级key
+ *   例如: 以下结构应推断路径为 user.info.district
+        object (name: "user")
+          └─ object (name: "info")
+            └─ dropdown1 (name: "district", defaultValue: "Beijing")
+ * * array 父级key.[子级索引]
+ *   例如: 以下结构应推断路径为 user.activityList[${index}]
+        object (name: "user")
+          └─ array (name: "activityList")
+            └─ text (name: "self", defaultValue: "Hello")
+
+ * * array-object 父级key.[子级索引]子级key
+ *   例如: 以下结构应推断路径为 user.activityList[${index}].name
+        object (name: "user")
+          └─ array-object (name: "activityList")
+            └─ text (name: "name", defaultValue: "Hello")
+ */
 function initDefaultValuesToModel() {
   function loopItems(key: string, parentKey: string, type: string, items: IDynamicFormItem[]) {
     let i = 0;
@@ -166,14 +192,15 @@ function initDefaultValuesToModel() {
           currentKey = (key ? key + '.' : '') + item.name;
           break
         case 'array':
-          currentKey = (parentKey ? parentKey + '.' : '') + `[${i}]`;
+          currentKey = (parentKey ? parentKey : '') + `[${i}]`;
           break;
         case 'array-object':
-          currentKey = (parentKey ? parentKey + '.' : '') + `[${i}]` + item.name;
+          currentKey = (parentKey ? parentKey : '') + `[${i}].` + item.name;
           break;
       }
       if (item.children) {
-        loopItems(currentKey, key, item.type || '', item.children);
+        const childParentKey = (item.type === 'flat-simple' || item.type === 'flat-group') ? parentKey : currentKey;
+        loopItems(currentKey, childParentKey, item.type || '', item.children);
       }
       if (item.defaultValue !== undefined) {
         const oldValue = accessFormModel(currentKey, false, undefined);
@@ -206,6 +233,9 @@ const formRef : IDynamicFormRef = {
       throw new Error('Form instance is not create.');
     return formEditor.value
   },
+  getGlobalParams() {
+    return props.globalParams;
+  },
   getFormItemControlRefsByType: getFormItemControlRefsByType as any,
   getFormItemControlRef: getFormItemControlRef as any,
   submit() { return this.getFormRef().validate(); },
@@ -222,6 +252,7 @@ const formRef : IDynamicFormRef = {
   },
   dispatchMessage,
   dispatchReload,
+  emitMessage: (m, ...p) => emit(m as any, ...p),
 };
 
 provide('formRef', formRef);

+ 1 - 9
src/components/dynamic/wrappers/PickerIdField.vue

@@ -4,7 +4,7 @@
     v-bind="$attrs"
     :singleValue="true"
     :modelValue="!(modelValue instanceof Array) ? [modelValue || ''] : modelValue"
-    @update:modelValue="handleUpdateModelValue"
+    @update:modelValue="emit('update:modelValue', $event)"
   />
 </template>
 
@@ -27,14 +27,6 @@ const loader = useDataLoader<PickerIdFieldOption[]>(async () => {
   immediate: true,
 });
 
-function handleUpdateModelValue(value: (string|number)[]) {
-  if (value.length === 1) {
-    emit('update:modelValue', value[0]);
-    return;
-  }
-  emit('update:modelValue', value);
-}
-
 defineExpose({
   reload() {
     loader.load();

+ 3 - 0
src/components/form/FormContext.ts

@@ -154,6 +154,7 @@ export function useFieldChildValueInjector<T>(
   },
   fieldClick?: () => void,
   initialValue?: T,
+  solveValue?: (value: T) => T,
 ) {
   const cellContext = useCellContext();
   const context = useInjectFormItemContext();
@@ -175,6 +176,8 @@ export function useFieldChildValueInjector<T>(
    * @param newValue 新值
    */
   function updateValue(newValue: T) {
+    if (solveValue)
+      newValue = solveValue(newValue);
     if (secondParentContext)
       secondParentContext.updateValue(newValue);
     else

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

@@ -77,6 +77,11 @@ export interface PickerFieldProps extends Omit<PickerProps, 'value'> {
    * 是否只读
    */
   readonly?: boolean,
+  /**
+   * 在数据值更新后自动处理
+   * @default 默认有一个回调,在只有一列时,转换为单值,多列时,转换为数组。
+   */
+  valueSolve?: (value: (string | number)[]) => any,
 }
 
 const emit = defineEmits([ 'update:modelValue', 'cancel', 'confirm', 'selectTextChange', 'tempValueChange' ]);
@@ -90,6 +95,7 @@ const props = withDefaults(defineProps<PickerFieldProps>(), {
   }),
   showSelectText: true,
   singleValue: false,
+  valueSolve: (value: any) => (value.length === 1 ? value[0] : value),
 });
 
 const popupShow = ref(false);
@@ -106,6 +112,7 @@ const {
     popupShow.value = true;
   },
   props.initalValue,
+  props.valueSolve,
 );
 
 const {

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

@@ -80,7 +80,7 @@ import UploaderListItem from './UploaderListItem.vue';
 import FlexView from '../layout/FlexView.vue';
 import FlexCol from '../layout/FlexCol.vue';
 import type { UploaderAction, UploaderItem } from './Uploader';
-import { Debounce, LogUtils } from '@imengyu/imengyu-utils';
+import { Debounce, formatError, LogUtils } from '@imengyu/imengyu-utils';
 import Text from '../basic/Text.vue';
 import { actionSheet } from '../dialog/CommonRoot';
 
@@ -536,7 +536,7 @@ function startUploadItem(item: UploaderItem) {
       item,
       onError(error) {
         item.state = 'fail';
-        item.message = ('' + error) || '上传失败';
+        item.message = ('' + formatError(error)).replace('Error: ', '');
         updateListItem(item);
         reject(error);
         LogUtils.printLog(TAG, 'error', `上传文件 ${item.filePath} 失败,错误信息:${error}`);

+ 7 - 0
src/pages.json

@@ -102,6 +102,13 @@
       }
     },
     {
+      "path": "pages/home/village/upgrade/upgrade-village",
+      "style": {
+        "navigationBarTitleText": "升级村社",
+        "navigationStyle": "custom"
+      }
+    },
+    {
       "path": "pages/home/village/orders",
       "style": {
         "navigationBarTitleText": "我的订单",

+ 18 - 14
src/pages/dig/forms/list.vue

@@ -46,8 +46,18 @@
                 <FlexCol>
                   <H4 :size="36">{{ item.title }}</H4>
                   <Text :size="23">{{ item.desc }}</Text>
+                  <Text fontConfig="secondText" :text="item.from" />
                 </FlexCol>
               </Touchable>
+              <FlexCol>
+                <FlexRow>
+                  <FrameButton :text="item.statusText" size="midium" @click="navTo('/pages/dig/about/goving')" />
+                </FlexRow>
+                <FlexRow gap="gap.md">
+                  <IconButton icon="appreciate-light-fill" size="30" :text="item.likes" color="primary" />
+                  <IconButton icon="appreciate-light" size="30" :rotate="180" :text="item.disLikes" color="primary" />
+                </FlexRow>
+              </FlexCol>
             </BoxMid>
           </FlexCol>
           <template #empty>
@@ -92,6 +102,8 @@ import { getVillageInfoForm } from './forms';
 import CommonTopBanner from '@/common/components/CommonTopBanner.vue';
 import PrimaryButton from '@/common/components/PrimaryButton.vue';
 import BoxMid from '@/common/components/box/BoxMid.vue';
+import FrameButton from '@/common/components/FrameButton.vue';
+import IconButton from '@/components/basic/IconButton.vue';
 
 const subTitle = ref('');
 const searchText = ref('');
@@ -102,19 +114,7 @@ const authStore = useAuthStore();
 
 const error = ref('');
 
-const listLoader = useSimplePageListLoader<{
-  id: number,
-  image: string,
-  title: string,
-  desc: string,
-  villageVolunteerId: number,
-}, {
-  villageId: number,  
-  villageVolunteerId: number,
-  collectModuleId: number,
-  subId: number,
-  subKey: string,
-}>(8, async (page, pageSize, params) => {
+const listLoader = useSimplePageListLoader(8, async (page, pageSize, params) => {
   if (!params )
     throw new Error("未传入参数,当前页面需要参数");
   if (!params.collectModuleId)
@@ -139,7 +139,11 @@ const listLoader = useSimplePageListLoader<{
       villageVolunteerId: item.villageVolunteerId,
       desc: DataDateUtils.formatDate(item.updatedAt, 'YYYY-MM-dd') + (
         authStore.isAdmin || isManagement.value ? (' 投稿人:' + item.villageVolunteerName) : ''
-      )
+      ),
+      from: '投稿人:' + item.villageVolunteerName,
+      disLikes: item.dislikeNum.toString(),
+      likes: item.likeNum.toString(),
+      statusText: item.statusText,
     }
   })
   return {