Ver código fonte

📦 修改点亮页细节问题

快乐的梦鱼 1 mês atrás
pai
commit
7e1397e418

+ 63 - 0
src/common/components/Construction.vue

@@ -0,0 +1,63 @@
+<template>
+  <FlexCol center :height="height" :padding="padding" :gap="gap">
+    <view class="construction-frame">
+      <view class="construction-inner">
+        <FlexCol center :gap="16" :padding="[40, 32]">
+          <Icon icon="warning-filling" :size="56" color="#f5c518" />
+          <Text :text="title" fontConfig="title" textAlign="center" bold />
+          <Text :text="text" fontConfig="subText" textAlign="center" color="text.second" />
+          <slot />
+        </FlexCol>
+      </view>
+    </view>
+  </FlexCol>
+</template>
+
+<script setup lang="ts">
+import Icon from '@/components/basic/Icon.vue';
+import Text from '@/components/basic/Text.vue';
+import FlexCol from '@/components/layout/FlexCol.vue';
+
+withDefaults(defineProps<{
+  /** 说明文字 */
+  text?: string;
+  /** 标题 */
+  title?: string;
+  /** 占位区域高度 */
+  height?: number | string;
+  /** 外层内边距 */
+  padding?: number | number[];
+  /** 内容间距 */
+  gap?: number | string;
+}>(), {
+  text: '此功能正在开发中,敬请期待',
+  title: '开发建设中',
+  height: 300,
+  padding: 30,
+  gap: 0,
+});
+</script>
+
+<style lang="scss" scoped>
+.construction-frame {
+  width: 100%;
+  max-width: 640rpx;
+  padding: 10rpx;
+  border-radius: 20rpx;
+  background-color: #f5c518;
+  background-image: repeating-linear-gradient(
+    -45deg,
+    #1a1a1a 0,
+    #1a1a1a 18rpx,
+    #f5c518 18rpx,
+    #f5c518 36rpx
+  );
+  box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.08);
+}
+
+.construction-inner {
+  border-radius: 14rpx;
+  background: #fff;
+  overflow: hidden;
+}
+</style>

+ 15 - 4
src/pages/home/components/LightMap.vue

@@ -105,6 +105,8 @@ const props = defineProps<{
 }>();
 
 const regionLoader = useSimpleDataLoader(async () => {
+  console.log('regionLoader', props.city);
+  
   if (!props.city)
     return [];
   return (await CommonContent.searchRegion(props.city)).map(p => ({
@@ -113,6 +115,8 @@ const regionLoader = useSimpleDataLoader(async () => {
   }));
 }, false);
 const mapLoader = useSimpleDataLoader<MapMarker[]>(async () => {
+  console.log('mapLoader', selectedRegion.value);
+  
   mapCtx.removeMarkers({
     markerIds: Array.from(villageData.keys()),
   })
@@ -199,10 +203,17 @@ const isEmptyRegion = computed(() => {
 function onMarkerTap(e: any) {
   if (props.isLightMode) {
     emit('update:isLightMode', false);
-    navTo('/pages/home/light/submit', {
-      villageId: e.markerId,
-    });
-    return;
+    const village = villageData.get(e.markerId);
+    if (village) {
+      console.log('village', village);
+      
+      navTo('/pages/home/light/submit', {
+        villageId: village.id,
+        unit: (village.city as string) + (village.district as string) + (village.township as string),
+        regionId: village.region,
+      });
+      return;
+    }
   }
   const village = villageData.get(e.markerId);
   if (village) {

+ 1 - 1
src/pages/home/index.vue

@@ -92,7 +92,7 @@
       <Button 
         icon="https://xy.wenlvti.net/app_static/images/home/IconLight.png" 
         radius="radius.lg" :padding="[10, 30]" 
-        @click="navTo('/pages/home/light/submit-map', { city: currentCity })"
+        @click="requireLogin(async () => navTo('/pages/home/light/submit-map', { city: currentCity }), '登录后才能点亮村社哦!')"
       >
         点亮村社
       </Button>

+ 178 - 0
src/pages/home/light/form/volunteer.ts

@@ -0,0 +1,178 @@
+import CommonContent from "@/api/CommonContent";
+import VillageApi from "@/api/inhert/VillageApi";
+import { useAliOssUploadCo } from "@/common/components/upload/AliOssUploadCo";
+import type { IDynamicFormItemCallbackAdditionalProps, IDynamicFormOptions, IDynamicFormRef } from "@/components/dynamic";
+import type { CheckBoxTreeListProps } from "@/components/dynamic/wrappers/CheckBoxTreeList.vue";
+import type { PickerIdFieldProps } from "@/components/dynamic/wrappers/PickerIdField";
+import type { RadioValueProps } from "@/components/dynamic/wrappers/RadioValue";
+import type { FieldProps } from "@/components/form/Field.vue";
+import type { FormProps } from "@/components/form/Form.vue";
+import type { UploaderFieldProps } from "@/components/form/UploaderField.vue";
+import type { RuleItem } from "async-validator";
+import type { Ref } from "vue";
+
+export function getVolunteerForm(options: {
+  canSetCatalog: boolean,
+  villageId: number,
+  onlyPassword?: boolean,
+  noPassword?: boolean,
+  isNew: Ref<boolean>,
+  formRef: Ref<IDynamicFormRef|undefined>,
+}) : IDynamicFormOptions {
+  return {
+    formItems: [
+      {
+        name: 'groupBase',
+        type: 'flat-simple',
+        show: { callback: () => !options.noPassword },
+        children: [
+          { 
+            label: '登录账号', name: 'username', type: 'text',
+            additionalProps: { 
+              placeholder: '请输入登录账号',
+            },
+            rules: [{ required: true, message: '请输入登录账号' }],
+            show: { callback: () => options.isNew.value },
+          },
+          {
+            label: '密码',
+            name: 'password',
+            type: 'text',
+            additionalProps: { 
+              placeholder: '请输入密码',
+              type: 'password',
+            } as FieldProps,
+            rules: [{ required: true, message: '请输入密码' }],
+            show: { callback: () => options.isNew.value || options.onlyPassword === true },
+          },
+          {
+            label: '确认密码',
+            name: 'passwordRepeat',
+            type: 'text',
+            additionalProps: { 
+              placeholder: '请再输入一次密码',
+              type: 'password',
+            } as FieldProps,
+            rules: [
+              { required: true, message: '请再输入一次密码' },
+              {
+                async validator(rule, value) {
+                  if (value != options.formRef.value?.getValueByPath('password'))
+                    throw '两次输入密码不一致,请检查';
+                },
+              }
+            ] as RuleItem[],
+            show: { callback: () => options.isNew.value || options.onlyPassword === true },
+          },
+        ]
+      },
+      {
+        name: 'groupExtra',
+        type: 'flat-simple',
+        show: { callback: () => options.onlyPassword !== true },
+        childrenColProps: {
+          span: 24,
+        },
+        children: [
+          {
+            label: '真实名称', name: 'name', type: 'text',
+            additionalProps: { placeholder: '请输入真实名称' },
+            rules: [{ required: true, message: '请输入真实名称' }],
+          },
+          {
+            label: '手机号', name: 'mobile', type: 'text',
+            additionalProps: { placeholder: '请输入手机号' },
+            rules: [{ required: true, message: '请输入手机号' }],
+          },
+          { 
+            label: '区域', name: 'regionId', type: 'select-id',
+            additionalProps: {
+              placeholder: '请选择区域',
+              disabled: { callback: () => !options.isNew.value },
+              loadData: async () => (await CommonContent.getCategoryList(1)).map(p => ({ text: p.title, value: p.id, raw: p }))
+            } as IDynamicFormItemCallbackAdditionalProps<PickerIdFieldProps>,
+            rules: [{ required: true, message: '请选择区域' }],
+          },
+          {
+            label: '性别', name: 'sex', type: 'radio-value',
+            additionalProps: {
+              options: [
+                { text: '男', value: 1 },
+                { text: '女', value: 2 }
+              ]
+            } as RadioValueProps,
+          },
+          { 
+            label: '头像', name: 'image', type: 'uploader',
+            additionalProps: {
+              single: true,
+              maxFileSize: 1024 * 1024 * 10,
+              upload: useAliOssUploadCo('xiangyuan/volunteer/images')
+            } as UploaderFieldProps,
+          },
+          {
+            label: '类型', name: 'type', type: 'radio-value',
+            additionalProps: {
+              options: [
+                { text: '志愿者', value: 'volunteer' },
+                { text: '社区工作者', value: 'staff' }
+              ]
+            } as RadioValueProps,
+            rules: [{ required: true, message: '请选择类型' }],
+          },
+          { 
+            label: '工作单位', name: 'unit', type: 'text', additionalProps: { placeholder: '请输入手机号' } ,
+            rules: [{ required: true, message: '请输入手机号' }],
+            show: { callback: () => options.formRef.value?.getValueByPath('type') === 'staff' },
+          },
+          { 
+            label: '职位', name: 'job', type: 'text', additionalProps: { placeholder: '请输入手机号' } ,
+            rules: [{ required: true, message: '请输入手机号' }],
+            show: { callback: () => options.formRef.value?.getValueByPath('type') === 'staff' },
+          },
+          { 
+            label: '手机号', name: 'mobile', type: 'text', additionalProps: { placeholder: '请输入手机号' } ,
+            rules: [{ required: true, message: '请输入手机号' }],
+          },
+          { label: '现居地址', name: 'address', type: 'text', additionalProps: { placeholder: '请输入现居地址' } },
+          { 
+            label: '个人介绍', 
+            name: 'intro', 
+            type: 'textarea', 
+            additionalProps: { 
+              placeholder: '请输入个人介绍',
+              showWordLimit: true,
+              maxLength: 200,
+            } as FieldProps,
+          },
+          ...(options.canSetCatalog ? [{ 
+            label: '采集版块', name: 'catalogIds', type: 'check-box-tree', 
+            additionalProps: { 
+              placeholder: '请选择采集版块',
+              vertical: true,
+              multiple: true,
+              loadData: async (pid) => (await VillageApi.getCatalogList(options.villageId, undefined, pid)).map((p) => ({
+                text: p.title,
+                value: p.id,
+                hasChildren: p.haschild,
+              })),
+            } as CheckBoxTreeListProps,
+          }]: []),
+          { 
+            label: '村落认领说明', name: 'claimReason', type: 'text', 
+            additionalProps: { placeholder: '请输入村落认领说明' } ,
+            show: { callback: () => options.isNew.value },
+          },
+        ]
+      },
+    ],
+    formAdditionaProps: {
+      labelWidth: '160rpx',
+      labelAlign: 'right',
+      innerStyle: {
+        radius: '10rpx',
+      },
+    } as Omit<FormProps, 'model'>,
+  }
+
+}

+ 1 - 0
src/pages/home/light/submit-map.vue

@@ -21,6 +21,7 @@ const currentLocation = useGetCurrentLocation({
 <template>
   <LightMap 
     full
+    :city="querys.city"
     :lonlat="currentLocation.currentLonlat.value"
     :isLightMode="true" 
     @getCurrentLonlat="currentLocation.getCurrentExactLocation"

+ 25 - 7
src/pages/home/light/submit.vue

@@ -66,13 +66,13 @@ import { closeToast, toast } from '@/components/dialog/CommonRoot';
 import { showError } from '@/common/composeabe/ErrorDisplay';
 import { useLoadQuerys } from '@/components/composeabe/LoadQuerys';
 import { onMounted, ref } from 'vue';
-//import { getVolunteerForm } from '@/pages/dig/admin/data/volunteer';
 import VillageApi, { VolunteerInfo } from '@/api/inhert/VillageApi';
 import type { IDynamicFormOptions, IDynamicFormRef } from '@/components/dynamic';
 import { waitTimeOut } from '@imengyu/imengyu-utils';
+import { getVolunteerForm } from './form/volunteer';
 
 /**
- * 分享注册页面
+ * 点亮村社页面
  */
 
 const authStore = useAuthStore();
@@ -80,24 +80,42 @@ const { init } = useAppInit();
 
 const { querys } = useLoadQuerys({ 
   villageId: 0,  
+  regionId: 0,
+  unit: '',
 });
-const step = ref<'register'|'finished'|'error'>('register');
+const step = ref<'register' |'add'|'finished'|'error'>('register');
 
 onMounted(async () => {
   if (!querys.value.villageId) {
     step.value = 'error';
     return;
   }
+
+  //如果已登录,则尝试获取志愿者信息,有注册志愿者,则显示认领当前村落表单
+  /* if (authStore.isLogged) {
+    try {
+      const volunteerInfo = await VillageApi.getVolunteerInfo();
+      if (volunteerInfo) {
+        step.value = 'add';
+
+
+        return;
+      }
+    } catch {
+    }
+  } */
+
+
   await waitTimeOut(1000);
-  registerFormDefine.value = {
-    formItems: [],
-  }/* getVolunteerForm({
+  registerFormDefine.value = getVolunteerForm({
     canSetCatalog: false,
     villageId: querys.value.villageId,
     onlyPassword: false,
     isNew: ref(true),
     formRef: registerFormRef,
-  }) */;
+  });
+  registerFormModel.value.regionId = querys.value.regionId;
+  registerFormModel.value.unit = querys.value.unit;
 });
 
 async function loginWechat() {

+ 2 - 2
src/pages/home/village/index.vue

@@ -31,7 +31,7 @@
     </Popup>
     <Height :height="150" />
   </FlexCol>
-  <Empty v-else description="请选择村庄" />
+  <Around v-else />
 </template>
 
 <script setup lang="ts">
@@ -48,8 +48,8 @@ import StatusBarSpace from '@/components/layout/space/StatusBarSpace.vue';
 import Button from '@/components/basic/Button.vue';
 import Popup from '@/components/dialog/Popup.vue';
 import VillageMyFollow from '../components/VillageMyFollow.vue';
-import Empty from '@/components/feedback/Empty.vue';
 import type { VillageListItem } from '@/api/light/LightVillageApi';
+import Around from './recommed/around.vue';
 
 const tab = ref('card');
 const villageStore = useVillageStore();

+ 7 - 11
src/pages/home/village/recommed/around.vue

@@ -1,20 +1,16 @@
 <template>
-  <FlexCol>
+  <FlexCol padding="space.sm">
     <HomeTitle title="周边村社" />
+    <Construction
+      text="此处在未选择村庄时可以推荐附近优秀村社信息。等待后端添加接口"
+    />
     <MasonryGrid>
       <MasonryGridItem
         v-for="(item, i) in recommendLoader.content.value"
         :key="i"
         :width="340"
       >
-        <IndexCommonImageItem
-          :image="item.image"
-          :title="item.title"
-          :desc="item.desc"
-          :userName="item.userName"
-          :likes="item.likes"
-          :isLike="item.isLike"
-        />
+
       </MasonryGridItem>
     </MasonryGrid>
   </FlexCol>
@@ -30,13 +26,13 @@ import { useSimpleDataLoader } from '@/components/composeabe/loader/SimpleDataLo
 import { useVillageStore } from '@/store/village';
 import LightVillageApi from '@/api/light/LightVillageApi';
 import CommonContent from '@/api/CommonContent';
+import Result from '@/components/feedback/Result.vue';
+import Construction from '@/common/components/Construction.vue';
 
 const villageStore = useVillageStore();
 const recommendLoader = useSimpleDataLoader(async () => {
   if (!villageStore.currentRegion)
     return [];
-  const regionId = await CommonContent.getCategoryList(villageStore.currentRegion);
-  const res = await LightVillageApi.getVillageList(1, villageStore.currentRegion, undefined, 1, 20);
 
 
   return [];