Explorar el Código

按要求修改表单中的问题

快乐的梦鱼 hace 3 meses
padre
commit
1192aef323

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

@@ -7,6 +7,7 @@
     <view class="d-flex flex-row gap-sss align-center mt-2">
       <Button icon="browse" text="预览" size="small" @click="preview" />
       <Button icon="edit" text="编辑" size="small" @click="edit" type="primary" />
+      <text v-if="maxLength > 0">{{ modelValue.length }}/{{ maxLength }} 字</text>
     </view>
   </view>
 </template>
@@ -17,12 +18,15 @@ import { navTo } from '@/components/utils/PageAction';
 import Parse from '@/components/display/parse/Parse.vue';
 import Button from '@/components/basic/Button.vue';
 
-
 const props = defineProps({	
   modelValue: { 
     type: String,
     default: null 
   },
+  maxLength: {
+    type: Number,
+    default: -1,
+  }
 })
 const emit = defineEmits(['update:modelValue'])
 let editorOpened = false;
@@ -37,6 +41,10 @@ function preview() {
 function edit() {
   editorOpened = true;
   uni.setStorage({
+    key: 'editorMaxLength',
+    data: props.maxLength,
+  })
+  uni.setStorage({
     key: 'editorContent',
     data: props.modelValue,
     success: () => navTo('/pages/editor/editor'),

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

@@ -238,7 +238,7 @@ export interface FieldProps {
   multiline?: boolean;
   /**
    * 多行文字下是否自动调整高度
-   * @default true
+   * @default false
    */
   autoHeight?: boolean;
   /**
@@ -441,7 +441,7 @@ const props = withDefaults(defineProps<FieldProps>(), {
   showRightArrow: () => propGetFormContext()?.fieldProps.value?.showRightArrow ?? false,
   disabled: false,
   readonly: false,
-  autoHeight: true,
+  autoHeight: false,
   maxLength: 100,
   modelValue: undefined,
   errorIcon: () => propGetThemeVar('FieldErrorIcon', 'prompt'),

+ 36 - 7
src/components/form/Uploader.vue

@@ -59,7 +59,7 @@
 </template>
 
 <script setup lang="ts">
-import { ref } from 'vue';
+import { h, ref } from 'vue';
 import { propGetThemeVar, useTheme, type TextStyle, type ViewStyle } from '../theme/ThemeDefine';
 import type { ToastInstance } from '../feedback/Toast.vue';
 import Toast from '../feedback/Toast.vue';
@@ -154,6 +154,13 @@ export interface UploaderProps {
    */
   intitalItems?: UploaderItem[];
   /**
+   * 选择文件类型
+   * * image:图片
+   * * video:视频
+   * @default 'image'
+   */
+  chooseType?: 'image'|'video'|'file';
+  /**
    * 上传处理。不提供则无法上传
    * @required true
    */
@@ -252,6 +259,7 @@ const props = withDefaults(defineProps<UploaderProps>(), {
   uploadWhenAdded: true,
   uploadQueueMode: 'all',
   listType: 'grid',
+  chooseType: 'image',
   itemSize: () => propGetThemeVar('UploaderItemSize', { width: 750 / 4 - 15, height: 750 / 4 - 15 }),
 });
 
@@ -272,10 +280,11 @@ function onUploadPress() {
   const items = props.onPickImage ?
     props.onPickImage() :
     new Promise<UploaderItem[]>((resolve, reject) => {
-      uni.chooseImage({
-        count: props.maxUploadCount - currentUpladList.value.length,
-      }).then((res) => {
-        resolve((res.tempFiles as UniApp.ChooseImageSuccessCallbackResultFile[]).map(item => {
+      function handleFiles(res: {
+        path: string;
+        size: number;
+      }[]) {
+        resolve(res.map((item) => {
           let isImage = typeof (item as any).type === 'string' ? (item as any).type.startsWith('image/') : false;
           for (const ext of isImageExt) {
             if (item.path.endsWith(ext)) {
@@ -290,8 +299,28 @@ function onUploadPress() {
             state: 'notstart',
             isImage,
           } as UploaderItem
-        }));
-      }).catch(reject);
+        }))
+      }
+
+      switch (props.chooseType) {
+        case 'video':
+          uni.chooseVideo().then((res) => handleFiles([
+            {
+              path: res.tempFilePath,
+              size: res.size,
+            }
+          ])).catch(reject);
+          break;
+        case 'file':
+          uni.chooseFile().then((res) => handleFiles(res.tempFiles as { path: string; size: number; }[])).catch(reject);
+          break;
+        default:
+        case 'image':
+          uni.chooseImage({
+            count: props.maxUploadCount - currentUpladList.value.length,
+          }).then((res) => handleFiles(res.tempFiles as { path: string; size: number; }[])).catch(reject);
+          break;
+      }
     });
 
   items

+ 1 - 1
src/pages/dig/forms/common.vue

@@ -6,7 +6,7 @@
         ref="formRef"
         :formDefine="formDefine"
         :formProps="({
-          labelWidth: '160rpx',
+          labelWidth: '200rpx',
           labelAlign: 'left',
           innerStyle: {
             borderRadius: '20rpx',

+ 138 - 98
src/pages/dig/forms/forms.ts

@@ -95,7 +95,7 @@ const villageInfoBuildingForm : SingleForm = [VillageBulidingInfo, {
     {
       label: '建筑中的故事', 
       name: 'story', 
-      type: 'text', 
+      type: 'textarea', 
       defaultValue: '',
       params: {
         placeholder: '请输入建筑中的故事',
@@ -179,12 +179,12 @@ const villageInfoBuildingForm : SingleForm = [VillageBulidingInfo, {
       }] 
     },
     {
-      label: '始建时间', 
+      label: '始建时间(年)', 
       name: 'age', 
       type: 'number', 
-      defaultValue: 0,
+      defaultValue: 2025,
       params: {
-        min: 1900,
+        min: -50000,
         max: 2000,
       },
       rules:  [{
@@ -195,7 +195,7 @@ const villageInfoBuildingForm : SingleForm = [VillageBulidingInfo, {
     {
       label: '功能特点', 
       name: 'funcFeatures', 
-      type: 'text', 
+      type: 'textarea', 
       defaultValue: '',
       params: {
         placeholder: '请输入功能特点',
@@ -433,7 +433,7 @@ const villageInfoFolkCultureForm : SingleForm = [VillageBulidingInfo, {
     {
       label: '详情',
       name: 'details',
-      type: 'text',
+      type: 'textarea',
       defaultValue: '',
       params: {
         placeholder: '请输入详情',
@@ -494,7 +494,7 @@ const villageInfoFoodProductsForm : SingleForm = [VillageBulidingInfo, {
     {
       label: '详情',
       name: 'details',
-      type: 'text',
+      type: 'textarea',
       defaultValue: '',
       params: {
         placeholder: '请输入详情',
@@ -506,8 +506,53 @@ const villageInfoFoodProductsForm : SingleForm = [VillageBulidingInfo, {
     },
   ]
 }];
-
-//TODO: 图片上传组件
+const villageCommonContent : FormDefine = {
+  items: [
+    {
+      label: '标题',
+      name: 'title',
+      type: 'text',
+      defaultValue: '',
+      params: {
+        placeholder: '请输入标题',
+      },
+      rules: [{
+        required: true,
+        message: '请输入标题',
+      }]
+    },
+    {
+      label: '内容',
+      name: 'content',
+      type: 'richtext',
+      defaultValue: '',
+      params: {
+        placeholder: '请输入内容',
+        maxLength: 1000,
+      },
+      rules: [{
+        required: true,
+        message: '请输入内容',
+      }]
+    },
+    {
+      label: '图片',
+      name: 'images',
+      type: 'richtext',
+      defaultValue: '',
+      params: {
+        upload: useAliOssUploadCo('xiangyuan/common'),
+        maxFileSize: 1024 * 1024 * 20,
+        maxUploadCount: 20,
+      } as UploaderFieldProps,
+      rules: [{
+        required: true,
+        message: '请输入内容',
+      }]
+    },
+  ]
+};
+ 
 //TODO: 关联的文化资源ID
 
 const villageInfoForm : Record<string, Record<number, SingleForm>> = {
@@ -671,7 +716,7 @@ const villageInfoForm : Record<string, Record<number, SingleForm>> = {
           }] 
         }, 
         { 
-          label: '村落类型', 
+          label: '村落形成年代', 
           name: 'age',
           type: 'select-id', 
           params: {
@@ -1005,7 +1050,9 @@ const villageInfoForm : Record<string, Record<number, SingleForm>> = {
                 defaultValue: '',
                 params: {
                   placeholder: '请输入概括',
-                },
+                  maxLength: 300,
+                  showWordLimit: true, 
+                } as FieldProps,
                 rules: [{
                   required: true,
                   message: '请输入概括',
@@ -1030,7 +1077,9 @@ const villageInfoForm : Record<string, Record<number, SingleForm>> = {
                 defaultValue: '',
                 params: {
                   placeholder: '请输入突出价值',
-                },
+                  maxLength: 1000,
+                  showWordLimit: true, 
+                } as FieldProps,
                 rules: [{
                   required: true,
                   message: '请输入突出价值',
@@ -1043,73 +1092,44 @@ const villageInfoForm : Record<string, Record<number, SingleForm>> = {
     }],
   },
   'cultural': {
-    [1]: [CommonInfoModel, {
-      items: [
-        {
-          label: '内容',
-          name: 'content',
-          type: 'textarea',
-          defaultValue: '',
-          params: {
-            placeholder: '请输入内容',
-          },
-          rules: [{
-            required: true,
-            message: '请输入内容',
-          }]
-        }
-      ]
-    }],
-    [2]: [CommonInfoModel, {
-      items: [
-        {
-          label: '内容',
-          name: 'content',
-          type: 'textarea',
-          defaultValue: '',
-          params: {
-            placeholder: '请输入内容',
-          },
-          rules: [{
-            required: true,
-            message: '请输入内容',
-          }]
-        }
-      ]
-    }],
+    [1]: [CommonInfoModel, villageCommonContent],
+    [2]: [CommonInfoModel, villageCommonContent],
     [3]: [CommonInfoModel, {
       items: [
+        ...(villageCommonContent.items.slice(0, 2)),
         {
-          label: '内容',
-          name: 'content',
-          type: 'textarea',
+          label: '扫描件或图片',
+          name: 'images',
+          type: 'uploader',
           defaultValue: '',
           params: {
-            placeholder: '请输入内容',
-          },
+            upload: useAliOssUploadCo('xiangyuan/cultural/scan'),
+            maxFileSize: 1024 * 1024 * 20,
+            maxUploadCount: 20,
+          } as UploaderFieldProps,
           rules: [{
             required: true,
-            message: '请输入内容',
+            message: '请上传扫描件或图片',
           }]
-        }
-      ]
+        },
+      ],
     }],
     [4]: [CommonInfoModel, {
       items: [
+        ...villageCommonContent.items,
         {
-          label: '内容',
-          name: 'content',
-          type: 'textarea',
+          label: '视频',
+          name: 'video',
+          type: 'uploader',
           defaultValue: '',
           params: {
-            placeholder: '请输入内容',
-          },
-          rules: [{
-            required: true,
-            message: '请输入内容',
-          }]
-        }
-      ]
+            upload: useAliOssUploadCo('xiangyuan/cultural/video'),
+            chooseType: 'video',
+            maxFileSize: 1024 * 1024 * 20,
+            single: true,
+          } as UploaderFieldProps,
+        },
+      ],
     }],
   },
   'story': {
@@ -1180,7 +1200,9 @@ const villageInfoForm : Record<string, Record<number, SingleForm>> = {
           defaultValue: '',
           params: {
             placeholder: '请输入简介',
-          },
+            maxLength: 500,
+            showWordLimit: true, 
+          } as FieldProps,
           rules: [{
             required: true,
             message: '请输入简介',
@@ -1219,19 +1241,6 @@ const villageInfoForm : Record<string, Record<number, SingleForm>> = {
           }] 
         }, 
         {
-          label: '编号', 
-          name: 'code', 
-          type: 'text', 
-          defaultValue: '',
-          params: {
-            placeholder: '请输入编号',
-          },
-          rules:  [{
-            required: true,
-            message: '请输入编号',
-          }] 
-        }, 
-        {
           label: '位置', 
           name: 'position', 
           type: 'text', 
@@ -1283,13 +1292,24 @@ const villageInfoForm : Record<string, Record<number, SingleForm>> = {
           }],
         },
         {
+          label: '编号', 
+          name: 'code', 
+          type: 'text', 
+          defaultValue: '',
+          params: {
+            placeholder: '(可选)请输入编号',
+          },
+        }, 
+        {
           label: '环境特点', 
           name: 'environment', 
           type: 'textarea', 
           defaultValue: '',
           params: {
             placeholder: '请输入环境特点',
-          },
+            maxLength: 500,
+            showWordLimit: true, 
+          } as FieldProps,
           rules:  [{
             required: true,
             message: '请输入环境特点',
@@ -1302,7 +1322,9 @@ const villageInfoForm : Record<string, Record<number, SingleForm>> = {
           defaultValue: '',
           params: {
             placeholder: '请输入文化故事',
-          },
+            maxLength: 1000,
+            showWordLimit: true, 
+          } as FieldProps,
           rules:  [{
             required: true,
             message: '请输入文化故事',
@@ -1315,7 +1337,9 @@ const villageInfoForm : Record<string, Record<number, SingleForm>> = {
           defaultValue: '',
           params: {
             placeholder: '请输入保存状况',
-          },
+            maxLength: 500,
+            showWordLimit: true, 
+          } as FieldProps,
           rules:  [{
             required: true,
             message: '请输入保存状况',
@@ -1328,7 +1352,9 @@ const villageInfoForm : Record<string, Record<number, SingleForm>> = {
           defaultValue: '',
           params: {
             placeholder: '请输入功能特点',
-          },
+            maxLength: 300,
+            showWordLimit: true, 
+          } as FieldProps,
           rules:  [{
             required: true,
             message: '请输入功能特点',
@@ -1356,7 +1382,7 @@ const villageInfoForm : Record<string, Record<number, SingleForm>> = {
         { 
           label: '自然环境', 
           name: 'natural', 
-          type: 'text', 
+          type: 'textarea', 
           defaultValue: '',
           params: {
             placeholder: '请输入自然环境',
@@ -1369,7 +1395,7 @@ const villageInfoForm : Record<string, Record<number, SingleForm>> = {
         { 
           label: '选址', 
           name: 'siteSelection', 
-          type: 'text', 
+          type: 'textarea', 
           defaultValue: '',
           params: {
             placeholder: '请输入选址',
@@ -1382,7 +1408,7 @@ const villageInfoForm : Record<string, Record<number, SingleForm>> = {
         { 
           label: '格局', 
           name: 'structure', 
-          type: 'text', 
+          type: 'textarea', 
           defaultValue: '',
           params: {
             placeholder: '请输入格局',
@@ -1395,7 +1421,7 @@ const villageInfoForm : Record<string, Record<number, SingleForm>> = {
         { 
           label: '整体风貌', 
           name: 'overallStyle', 
-          type: 'text', 
+          type: 'textarea', 
           defaultValue: '',
           params: {
             placeholder: '请输入整体风貌',
@@ -1461,7 +1487,7 @@ const villageInfoForm : Record<string, Record<number, SingleForm>> = {
         {
           label: '营造智慧', 
           name: 'wisdom', 
-          type: 'text', 
+          type: 'textarea', 
           defaultValue: '',
           params: {
             placeholder: '请输入营造智慧',
@@ -1672,9 +1698,13 @@ const villageInfoForm : Record<string, Record<number, SingleForm>> = {
         {
           label: '文化故事', 
           name: 'content', 
-          type: 'textarea', 
+          type: 'richtext', 
           defaultValue: '',
-          params: { placeholder: '文化故事' },
+          params: { 
+            placeholder: '文化故事',
+            maxLength: 5000,
+            showWordLimit: true, 
+          } as FieldProps,
           rules: []
         },
         {
@@ -1796,7 +1826,7 @@ const villageInfoForm : Record<string, Record<number, SingleForm>> = {
         {
           label: '传承人情况',
           name: 'inheritor',
-          type: 'text',
+          type: 'textarea',
           defaultValue: '',
           params: {
             placeholder: '请输入传承人情况',
@@ -2303,7 +2333,7 @@ const villageInfoForm : Record<string, Record<number, SingleForm>> = {
         {
           label: '描述', 
           name: 'desc', 
-          type: 'text', 
+          type: 'textarea', 
           defaultValue: '',
           params: {
             placeholder: '请输入描述',
@@ -2340,7 +2370,7 @@ const villageInfoForm : Record<string, Record<number, SingleForm>> = {
           }] 
         },
         {
-          label: '预计时长(分钟)', 
+          label: '预计时长(小时)', 
           name: 'estimate', 
           type: 'number', 
           defaultValue: 1,
@@ -2419,7 +2449,9 @@ const villageInfoForm : Record<string, Record<number, SingleForm>> = {
           defaultValue: '',
           params: {
             placeholder: '请输入特色',
-          },
+            maxLength: 300,
+            showWordLimit: true, 
+          } as FieldProps,
           rules:  [{
             required: true,
             message: '请输入特色',
@@ -2432,7 +2464,9 @@ const villageInfoForm : Record<string, Record<number, SingleForm>> = {
           defaultValue: '',
           params: {
             placeholder: '请输入文化背景',
-          },
+            maxLength: 300,
+            showWordLimit: true, 
+          } as FieldProps,
           rules:  [{
             required: true,
             message: '请输入文化背景',
@@ -2445,7 +2479,9 @@ const villageInfoForm : Record<string, Record<number, SingleForm>> = {
           defaultValue: '',
           params: {
             placeholder: '请输入精彩推荐',
-          },
+            maxLength: 300,
+            showWordLimit: true, 
+          } as FieldProps,
           rules:  [{
             required: true,
             message: '请输入精彩推荐',
@@ -2458,7 +2494,9 @@ const villageInfoForm : Record<string, Record<number, SingleForm>> = {
           defaultValue: '',
           params: {
             placeholder: '请输入推荐描述',
-          },
+            maxLength: 300,
+            showWordLimit: true, 
+          } as FieldProps,
           rules:  [{
             required: true,
             message: '请输入推荐描述',
@@ -2471,7 +2509,9 @@ const villageInfoForm : Record<string, Record<number, SingleForm>> = {
           defaultValue: '',
           params: {
             placeholder: '请输入活动亮点',
-          },
+            maxLength: 300,
+            showWordLimit: true, 
+          } as FieldProps,
           rules:  [{
             required: true,
             message: '请输入活动亮点',

+ 24 - 22
src/pages/editor/editor.vue

@@ -5,6 +5,7 @@
         excludeKeys: ['direction', 'date', 'lineHeight', 'letterSpacing', 'listCheck'],
         iconSize: '18px'
       }"
+      :maxlength="maxLength"
       @init="initEditor"
       @input="inputOver"
       @upinImage="upinImage"
@@ -20,12 +21,16 @@
 </template>
 
 <script setup lang="ts">
+import { ref } from 'vue';
+import { confirm } from '@/components/utils/DialogAction';
+import { back, backAndCallOnPageBack } from '@/components/utils/PageAction';
 import { showError } from '@/common/composeabe/ErrorDisplay';
 import spEditor from '@/uni_modules/sp-editor/components/sp-editor/sp-editor.vue';
 import XBarSpace from '@/components/layout/space/XBarSpace.vue';
 import Button from '@/components/basic/Button.vue';
-import { confirm } from '@/components/utils/DialogAction';
-import { back, backAndCallOnPageBack } from '@/components/utils/PageAction';
+import CommonContent from '@/api/CommonContent';
+
+const maxLength = ref(-1);
 
 function cancel() {
   confirm({
@@ -37,8 +42,6 @@ function cancel() {
   })
 }
 function save() {
-  console.log('save', currentContent);
-  
   uni.setStorage({
     key: 'editorContent',
     data: currentContent,
@@ -66,6 +69,12 @@ function overMax(e: { html: string; text: string; }) {
 }
 function initEditor(editor: any) {
   uni.getStorage({
+    key: 'editorMaxLength',
+    success: (success) => {
+      maxLength.value = parseInt(success.data);
+    },
+  })
+  uni.getStorage({
     key: 'editorContent',
     success: (success) => {
       editor.setContents({
@@ -82,27 +91,20 @@ function initEditor(editor: any) {
  * @param {Object} editorCtx
  */
 function upinImage(tempFiles: any, editorCtx: any) {
-  /**
-   * 本地临时插入图片预览
-   * 注意:这里仅是示例本地图片预览,因为需要将图片先上传到云端,再将图片插入到编辑器中
-   * 正式开发时,还请将此处注释,并解开下面 使用 uniCloud.uploadFile 上传图片的示例方法 的注释
-   * @tutorial https://uniapp.dcloud.net.cn/api/media/editor-context.html#editorcontext-insertimage
-   */
+  let path;
   // #ifdef MP-WEIXIN
-  // 注意微信小程序的图片路径是在tempFilePath字段中
-  editorCtx.insertImage({
-    src: tempFiles[0].tempFilePath,
-    width: '80%', // 默认不建议铺满宽度100%,预留一点空隙以便用户编辑
-    success: function () {}
-  })
+  path = tempFiles[0].tempFilePath; 
   // #endif
-
   // #ifndef MP-WEIXIN
-  editorCtx.insertImage({
-    src: tempFiles[0].path,
-    width: '80%', // 默认不建议铺满宽度100%,预留一点空隙以便用户编辑
-    success: function () {}
-  })
+  path = tempFiles[0].path;
   // #endif
+
+  CommonContent.uploadFile(path, 'image', 'file').then((res) => {
+    editorCtx.insertImage({
+      src: res.fullurl,
+      width: '80%',
+      success: function () {}
+    })
+  });
 }
 </script>

+ 1 - 1
src/pages/user/login.vue

@@ -6,7 +6,7 @@
         <Form 
           :model="loginFormModel"
           :rules="loginFormRules"
-          labelWidth="100rpx"
+          labelWidth="140rpx"
         >
           <Field
             label="用户名"