Browse Source

界面优化

快乐的梦鱼 2 days ago
parent
commit
28558b17ba

+ 4 - 1
src/App.vue

@@ -1,5 +1,4 @@
 <style lang="scss">
-	@import "@/common/scss/common.scss";
 	@import "@/common/scss/global/base.scss";
 </style>
 
@@ -44,4 +43,8 @@ configTheme((theme) => {
 <style>
 	/*每个页面公共css */
   @import "@/static/css/font.css";
+
+  page {
+    background: #F8F8F8;
+  }
 </style>

+ 3 - 0
src/common/components/form/Recorder.vue

@@ -103,6 +103,7 @@ defineOptions({
         icon="record-filling"
         :size="40" 
         :buttonSize="60"
+        backgroundColor="button"
         color="danger"
         shape="round"
         @click="startRecord" 
@@ -113,12 +114,14 @@ defineOptions({
           shape="round"
           :size="30" 
           :buttonSize="50"
+          backgroundColor="button"
           color="danger"
           @click="stopRecord" 
         />
         <IconButton 
           :icon="paused?'play-filling':'pause-filling'" shape="round" 
           :size="30" 
+          backgroundColor="button"
           :buttonSize="50"
           color="danger"
           @click="toggleRecord" 

+ 0 - 885
src/common/scss/common.scss

@@ -1,885 +0,0 @@
-page {
-  background: #F8F8F8;
-  color: #111111;
-}
-
-view {
-  font-size: 14px;
-  line-height: inherit;
-}
-
-.main {
-  padding: 32rpx;
-  &.white{
-    background: #fff;
-  }
-}
-
-.search {
-  margin-bottom: 20rpx;
-
-  ::v-deep .uni-searchbar__box {
-    border: 1px solid #6e6e6e;
-  }
-
-  &.with-button {
-    display: flex;
-    flex-direction: row;
-    justify-content: space-between;
-    align-items: center;
-    margin-bottom: 0;
-
-    ::v-deep {
-      .uni-searchbar {
-        width: 500rpx;
-      }
-      .u-button {
-        border-radius: 40rpx;
-      }
-    }
-  }
-}
-.text-center{
-  text-align: center!important;
-}
-.category {
-  display: flex;
-  margin-top: 40rpx;
-  margin-bottom: 38rpx;
-  align-items: flex-end;
-  &.sm{
-    .name{
-      font-size: 32rpx;
-    }
-  }
-  .name {
-    flex: 1;
-    font-size: 36rpx;
-    color: #111111;
-    font-weight: 600;
-    display: flex;
-  }
-
-  .more {
-    font-size: 24rpx;
-    color: #666666;
-  }
-}
-
-.artifact-list {
-  padding-bottom: 50rpx;
-  display: flex;
-  flex-wrap: wrap;
-  justify-content: space-between;
-
-  .item {
-    margin-bottom: 36rpx;
-    position: relative;
-    overflow: hidden;
-    width: calc(50% - 15rpx);
-
-    .image-wrap {
-      width: 330rpx;
-      height: 330rpx;
-      background-size: cover;
-      background-position: center;
-      border-radius: 20rpx;
-    }
-
-    .name {
-      font-weight: 800;
-      font-size: 30rpx;
-      color: #333333;
-      margin-top: 20rpx;
-      width: 100%;
-      text-align: center;
-      height: 40rpx;
-      overflow: hidden;
-      text-overflow: ellipsis;
-      white-space: nowrap;
-    }
-  }
-}
-.mask {
-  position: absolute;
-  left: 0;
-  top: 0;
-  width: 100%;
-  height: 100%;
-  background: linear-gradient(180deg, rgba(0, 0, 0, 0.1) 0%, rgba(0, 0, 0, 0) 100%);
-  display: flex;
-  align-items: center;
-  justify-content: center;
-
-  .iconfont {
-    font-size: 80rpx;
-    color: #fff;
-    position: absolute;
-  }
-}
-.post-list {
-  display: flex;
-  flex-wrap: wrap;
-  justify-content: space-between;
-
-
-  .item {
-    padding: 0;
-    margin-bottom: 38rpx;
-    background: #fff;
-    border-radius: 20rpx 20rpx 0 0;
-    overflow: hidden;
-    width: calc(50% - 10rpx);
-
-    &:active, &.pressed {
-      background: #efefef;
-    }
-
-    .image-wrap {
-      position: relative;
-      width: 330rpx;
-      height: 440rpx;
-      background: #fff center;
-      background-size: cover;
-
-      .like {
-        position: absolute;
-        right: 24rpx;
-        bottom: 20rpx;
-        z-index: 99;
-        color: #fff;
-        font-size: 24rpx;
-        &.liked{
-          color: #FF8719;
-          .iconfont {
-            color: #FF8719;
-          }
-        }
-        .iconfont {
-          font-size: 26rpx;
-          color: #fff;
-          display: inline-block;
-          margin-right: 6rpx;
-        }
-
-      }
-    }
-
-    .desc {
-      margin: 20rpx 16rpx 30rpx;
-      text-align: justify;
-      font-size: 28rpx;
-      color: #666666;
-      line-height: 48rpx;
-    }
-  }
-}
-.banner {
-  margin-top: 10rpx;
-  .swiper {
-    overflow: hidden;
-    height: 246rpx;
-    border-radius: 28rpx;
-    .item {
-      height: 100%;
-      image {
-        height: 100%;
-        width: 100%;
-        border-radius: 28rpx;
-        display: block;
-      }
-    }
-  }
-}
-
-.category-tag{
-  font-size: 24rpx;
-  color:#fff;
-  margin-left: 10rpx;
-  display: flex;
-  align-items: flex-end;
-  text{
-    display: inline-block;
-    background:#FF8719;
-    padding:6rpx 10rpx;
-  }
-  .triangle{
-    padding: 0;
-    background:#FF8719;
-    height:10rpx; // 增加高度
-    width:24rpx; // 调整为正方形
-    clip-path: polygon(0 100%, 100% 0, 100% 100%);
-  }
-}
-/** 图文列表 水平 */
-.complex-list-horizontal-1 {
-  &.lg{
-    .item{
-      image, .image-wrapper,.u-image{
-        width: 262rpx;
-        height: 286rpx;
-        overflow: hidden;
-      }
-      .info{
-        .name{
-          margin-bottom: 10rpx;
-        }
-        .desc{
-          line-height: 45rpx;
-        }
-      }
-    }
-  }
-  .item {
-    padding: 0;
-    margin-bottom: 30rpx;
-    background: #fff;
-    display: flex;
-    position: relative;
-    border-radius: 20rpx;
-    overflow: hidden;
-    image,.image-wrapper,.u-image {
-      display: block;
-      border-radius: 20rpx;
-      width: 170rpx;
-      height: 190rpx;
-      flex-shrink: 0;
-      margin-right: 30rpx;
-      overflow: hidden;
-      background-color: #efefef;
-    }
-
-    .info {
-      padding-right: 30rpx;
-      .name {
-        margin-top: 32rpx;
-        font-size: 30rpx;
-        color: #312520;
-        font-weight: 600;
-        margin-bottom: 16rpx;
-        line-height: 48rpx;
-      }
-      .desc {
-        text-align: justify;
-        font-size: 28rpx;
-        color: #666666;
-        line-height: 48rpx;
-      }
-    }
-  }
-}
-.complex-list-horizontal-2 {
-  display: flex;
-  flex-wrap: wrap;
-  justify-content: space-between;
-
-  .item {
-    padding: 0;
-    margin-bottom: 30rpx;
-    background: #fff;
-    display: flex;
-    flex-direction: column;
-    position: relative;
-    border-radius: 20rpx;
-    overflow: hidden;
-    width: calc(50% - 15rpx);
-
-    image,.image-wrapper,.u-image {
-      display: block;
-      border-radius: 20rpx;
-      width: 100%;
-      height: 300rpx;
-      flex-shrink: 0;
-      overflow: hidden;
-      background-color: #efefef;
-    }
-
-    .desc {
-      text-align: justify;
-      font-size: 28rpx;
-      color: #666666;
-      line-height: 48rpx;
-      padding: 10rpx 20rpx; 
-    }
-  }
-}
-.ellipsis-1 {
-  display: -webkit-box;
-  -webkit-box-orient: vertical;
-  -webkit-line-clamp: 1;
-  overflow: hidden;
-  text-overflow: ellipsis;
-}
-.ellipsis-2 {
-  display: -webkit-box;
-  -webkit-box-orient: vertical;
-  -webkit-line-clamp: 2;
-  overflow: hidden;
-  text-overflow: ellipsis;
-}
-.ellipsis-4 {
-  display: -webkit-box;
-  -webkit-box-orient: vertical;
-  -webkit-line-clamp: 4;
-  overflow: hidden;
-  text-overflow: ellipsis;
-}
-.entrance{
-  background: #FFFFFF;
-  padding:24rpx 38rpx;
-  border-radius: 20rpx;
-  margin-bottom: 42rpx;
-  margin-top: 10rpx;
-  display: flex;
-  flex-wrap: nowrap;
-  .item{
-    text-align: center;
-    width: 25%;
-    image{
-      width: 95rpx;
-      height: 95rpx;
-    }
-    .title{
-      font-weight: 600;
-      font-size: 28rpx;
-      color: #111111;
-      margin-top: 12rpx;
-    }
-  }
-
-}
-
-.news-simple-list-with-stats {
-  background: #fff;
-  padding: 32rpx 32rpx 32rpx;
-  margin: 0 -32rpx;
-  .item {
-    display: flex;
-    align-items: center;
-    margin-bottom: 50rpx;
-    height: 130rpx;
-    overflow: hidden;
-    &:last-child{
-      margin-bottom: 0;
-    }
-    image,.image-wrapper,.u-image  {
-      width: 230rpx;
-      height: 130rpx;
-      border-radius: 10rpx;
-      margin-right: 20rpx;
-    }
-
-    .info {
-      flex: 1;
-      .title {
-        font-size: 28rpx;
-        color: #111111;
-        line-height: 42rpx;
-        margin-bottom: 20rpx;
-      }
-      .name {
-        min-height: 76rpx;
-      }
-      .extra {
-        display: flex;
-        font-size: 24rpx;
-        color: #999999;
-        text.iconfont {
-          margin-right: 4rpx;
-          display: inline-block;
-          &.icon-view{
-            margin-left: 20rpx;
-          }
-          &.icon-fav{
-            margin-left: 20rpx;
-          }
-        }
-      }
-    }
-  }
-}
-
-::v-deep .swiper .wx-swiper-dot {
-  width: 16rpx;
-  height: 16rpx;
-  background: rgba(0,0,0,0.5);
-  border: 4rpx solid #fff;
-  border-radius: 50%;
-  transition: all 0.3s ease;
-}
-
-::v-deep .swiper .wx-swiper-dot-active {
-  width: 44rpx;
-  height: 16rpx;
-  background: #FF8719;
-  border-radius: 20rpx;
-  border: 4rpx solid #FFFFFF;
-  opacity: 1;
-}
-::v-deep  .swiper.right-indicator .wx-swiper-dots {
-  left: inherit;
-  right: -20rpx;
-}
-.compound-list.scene-list {
-  .item {
-    flex-direction: column;
-    height: 370rpx;
-    image{
-      display: block;
-      width: 100%;
-      height:282rpx;
-    }
-    .info{
-      display: flex;
-      padding:20rpx;
-      justify-content: center;
-      .name{
-        flex:1;
-        margin-top: 6rpx;
-      }
-      .desc{
-        color:#24515D;
-        font-size: 24rpx;
-        text.iconfont{
-          font-size: 24rpx;
-          color:#999999;
-          display: inline-block;
-          margin-left: 6rpx;
-        }
-      }
-    }
-  }
-}
-/**
-  上图下标题
- */
-.complex-list-vertical-1 {
-  display: flex;
-  justify-content: space-between;
-  flex-wrap: wrap;
-
-  .item {
-    width: calc(50% - 15rpx);
-    margin-bottom: 53rpx;
-    position: relative;
-    
-    image {
-      width: 100%;
-      height: 360rpx;
-      display: block;
-    }
-
-    .info {
-      text-align: center;
-      padding-top: 20rpx;
-      font-weight: bold;
-      font-size: 30rpx;
-      color: #312520;
-    }
-  }
-}
-.complex-list-vertical-2{
-  .item{
-    margin-bottom: 35rpx;
-    image{
-      width: 687rpx;
-      height: 287rpx;
-      display: block;
-      border-radius: 10rpx;
-    }
-    .info{
-      background: #FFFFFF;
-      display: flex;
-      padding:24rpx 20rpx 29rpx;
-      font-size: 24rpx;
-      color: #24515D;
-      align-items: center;
-      .name{
-        flex:1;
-        font-weight: 600;
-        font-size: 30rpx;
-        color: #111111
-      }
-      text.iconfont{
-        color:#999999;
-      }
-    }
-  }
-}
-/**
-  图文横向滑动
-**/
-.complex-swiper {
-  /* 小一号的尺寸 首页用 */
-  &.sm{
-    .swiper{
-      height: 254rpx;
-
-    }
-    .item{
-      height:100%;
-      width: 425rpx;
-    }
-    .name{
-      right:28rpx;
-      bottom: 22rpx;
-    }
-  }
-  &.lg{
-    .swiper{
-      height: 360rpx;
-
-      .swiper-item {
-        width: 580rpx;
-
-        &.active {
-          z-index: 10;
-
-          .item {
-            transform: scale(1);
-          }
-        }
-      }
-      .item{
-        width: 580rpx;
-        height: 360rpx;
-        transform: scale(0.8);
-        transition: transform 0.3s ease;
-        position: relative;
-      }
-    }
-  }
-  .swiper {
-    height: 300rpx;
-  }
-  .item {
-    width: 514rpx;
-    height: 300rpx;
-    position: relative;
-    border-radius: 20rpx;
-    overflow: hidden;
-    image {
-      width: 100%;
-      height: 100%;
-    }
-    .name {
-      position: absolute;
-      bottom: 14rpx;
-      right: 22rpx;
-      left: 22rpx;
-      color: #fff;
-      font-weight: 600;
-      font-size: 28rpx;
-    }
-  }
-}
-.threeD {
-  width: 36rpx;
-  height: 36rpx;
-  background: rgba(0, 0, 0, 0.57);
-  border-radius: 50%;
-  position: absolute;
-  top: 15rpx;
-  left: 205rpx;
-  z-index: 99;
-  text-align: center;
-
-  text {
-    color: #fff;
-    font-size: 24rpx;
-  }
-}
-page > view{
-  padding-bottom: 120rpx;
-}
-.img-banner {
-  height: 246rpx;
-  width: 100%;
-  border-radius: 20rpx;
-  margin-bottom: 40rpx;
-  overflow: hidden;
-  image {
-    height: 100%;
-    width: 100%;
-  }
-}
-
-.level-info {
-  padding: 48rpx 36rpx 36rpx;
-  background: #FFF2E6;
-  border-radius: 20rpx;
-  position: relative;
-  margin-bottom: 40rpx;
-  > view:first-child {
-    margin-bottom: 44rpx;
-  }
-
-  .label {
-    font-size: 28rpx;
-    color: #111111;
-    display: inline-block;
-  }
-
-  .value {
-    font-weight: bold;
-    font-size: 28rpx;
-    display: inline-block;
-    color: #333333;
-
-    .em {
-      font-family: Rockwell;
-      font-weight: 600;
-      font-size: 30rpx;
-      color: #FF8719;
-      display: inline-block;
-      margin-left: 35rpx;
-    }
-  }
-
-  .btn {
-    position: absolute;
-    top: 30rpx;
-    right: 30rpx;
-    border-radius: 10rpx;
-    border: 1px solid #FF8719;
-    padding: 15rpx 20rpx;
-    display: flex;
-    align-items: center;
-    font-weight: 400;
-    font-size: 28rpx;
-    color: #FF8719;
-
-    text.iconfont {
-      display: inline-block;
-      margin-right: 15rpx;
-      font-size: 40rpx;
-    }
-  }
-}
-.task-list{
-  .item{
-    display: flex;
-    align-items: center;
-    background: #fff;
-    margin-bottom: 36rpx;
-    padding:39rpx 27rpx 38rpx;
-    text.iconfont{
-      width: 91rpx;
-      height: 91rpx;
-      border-radius: 50%;
-      border: 1px solid #25515E;
-      text-align: center;
-      color: #25515E;
-      font-size: 60rpx;
-      line-height: 91rpx;
-      display: inline-block;
-      margin-right: 17rpx;
-    }
-    .btn{
-      background: #FF8719;
-      border-radius: 28rpx;
-      color:#fff;
-      font-size: 28rpx;
-      padding:14rpx 38rpx;
-      &.active{
-        background: #EFEFEF;
-        color:#999999;
-      }
-    }
-    .info{
-      flex:1;
-      .title{
-        font-weight: 600;
-        font-size: 30rpx;
-        color: #333333;
-        margin-bottom: 22rpx;
-      }
-      .desc{
-        font-weight: 400;
-        font-size: 24rpx;
-        color: #999999;
-      }
-    }
-  }
-}
-.people-list{
-  display: flex;
-  justify-content: space-between;
-  flex-wrap: wrap;
-  .item{
-    width: 214rpx;
-    background: #fff;
-    text-align: center;
-    position: relative;
-    margin-bottom: 24rpx;
-    padding-top: 80rpx;
-    padding-bottom: 40rpx;
-    border-radius: 10rpx;
-    image.avatar{
-      width: 90rpx;
-      height: 90rpx;
-      border-radius: 50%;
-      margin-bottom: 38rpx;
-    }
-    .name{
-      font-weight: 800;
-      font-size: 30rpx;
-      color: #333333;
-      margin-bottom: 20rpx;
-    }
-    .days{
-      font-weight: 500;
-      font-size: 24rpx;
-      color: #999999;
-    }
-    .rank{
-      position: absolute;
-      top: 35rpx;
-      left: 17rpx;
-      font-size: 48rpx;
-      line-height: 35rpx;
-      color:#B6B6B6;
-      font-style: italic;
-      font-family: Rockwell;
-      &.top{
-        color: #FF8719;
-        font-size: 60rpx;
-      }
-      .num-shadow{
-        width: 45rpx;
-        height: 45rpx;
-        position: absolute;
-        left: 30rpx;
-        top: 0;
-      }
-    }
-  }
-
-}
-button[type="primary"] {
-  background: #FF8719;
-  border-radius: 16rpx;
-  font-size: 28rpx;
-  padding: 8rpx;
-  color: #FFFFFF;
-  font-weight: 600;
-}
-
-.address-select {
-  position: relative;
-  width: 100%; // 添加宽度
-  height: 100%;
-}
-
-.input-wrapper {
-  width: 100%;
-  height: 100%;
-  pointer-events: none; /* 禁用内部元素的点击事件 */
-}
-
-.bottom-actions {
-  position: fixed;
-  bottom: 0;
-  left: 0;
-  right: 0;
-  display: flex;
-  align-items: center;
-  justify-content: flex-end;
-  width: 100%;
-  height: 75rpx;
-  background: #FFFFFF;
-
-  .action {
-    margin-left: 48rpx;
-    font-weight: 800;
-    font-size: 24rpx;
-    color: #191919;
-    display: flex;
-    align-items: center;
-
-    &:last-child {
-      margin-right: 70rpx;
-    }
-
-    .iconfont {
-      font-size: 30rpx;
-      margin-right: 14rpx;
-    }
-
-    .iconfont.icon-liked {
-      color: #FF8719;
-    }
-  }
-}
-
-.article {
-  .title {
-    font-weight: 800;
-    font-size: 36rpx;
-    color: #1E1E1E;
-    line-height: 60rpx;
-    margin-top: 10rpx;
-  }
-
-  .content {
-    padding-bottom: 100rpx;
-  }
-
-  .info {
-    display: flex;
-    align-items: center;
-    margin-top: 25rpx;
-    margin-bottom: 45rpx;
-
-    .author {
-      font-size: 24rpx;
-      color: #FF8719;
-      margin-right: 16rpx;
-    }
-
-    .time {
-      font-size: 24rpx;
-      color: #999999;
-    }
-  }
-}
-.main-img{
-  width: 100%;
-  height: 394rpx;
-  display: block;
-  image{
-    height: 100%;
-    width: 100%;
-  }
-}
-.article {
-  .title {
-    font-weight: 800;
-    font-size: 36rpx;
-    color: #1E1E1E;
-    line-height: 60rpx;
-    margin-top: 10rpx;
-  }
-
-  .content {
-    padding-bottom: 100rpx;
-  }
-
-  .info {
-    display: flex;
-    align-items: center;
-    margin-top: 25rpx;
-    margin-bottom: 45rpx;
-
-    .author {
-      font-size: 24rpx;
-      color: #FF8719;
-      margin-right: 16rpx;
-    }
-
-    .time {
-      font-size: 24rpx;
-      color: #999999;
-    }
-  }
-}

+ 9 - 4
src/components/basic/Icon.vue

@@ -8,9 +8,8 @@
   <text 
     v-else-if="iconData.type == 'iconfont'"
     :style="style"
-  >
-    {{ iconData.value }}
-  </text>
+    :class="['iconfont',iconData.value]"
+  />
 
   <!-- #ifdef H5 || APP-PLUS -->
   <view
@@ -72,7 +71,13 @@ const props = withDefaults(defineProps<IconProps>(), {
 });
 const iconData = computed(() => {
   const data = props.icon ? IconUtils.getIconDataFromMap(props.icon) : undefined;
-  if (!data) {
+  if (!data && props.icon && props.icon.startsWith('icon-')) {
+    return {
+      type: 'iconfont',
+      value: props.icon,
+      fontFamily: 'iconfont',
+    } as IconItem
+  } else if (!data) {
     return {
       type: 'image',
       value: props.icon,

+ 0 - 2
src/components/basic/IconButton.vue

@@ -51,7 +51,6 @@ export interface IconButtonProps extends IconProps {
   buttonSize?: number|string;
   /**
    * 按钮背景颜色
-   * @default 'button'
    */
   backgroundColor?: string;
 }
@@ -60,7 +59,6 @@ const emit = defineEmits(['click']);
 const theme = useTheme();
 const props = withDefaults(defineProps<IconButtonProps>(), {
   shape: 'custom',
-  backgroundColor: 'button',
   pressedBackgroundColor: () => propGetThemeVar('IconButtonPressedColor', 'pressed.white')
 });
 const style = computed(() => {

+ 46 - 0
src/pages/dig/components/TaskList.vue

@@ -0,0 +1,46 @@
+<script setup lang="ts">
+import Button from '@/components/basic/Button.vue';
+import Icon from '@/components/basic/Icon.vue';
+import Text from '@/components/basic/Text.vue';
+import FlexCol from '@/components/layout/FlexCol.vue';
+import FlexRow from '@/components/layout/FlexRow.vue';
+import Width from '@/components/layout/space/Width.vue';
+
+defineEmits(['click'])
+defineProps({
+  icon: {
+    type: String,
+    default: 'task-summary',
+  },
+  title: {
+    type: String,
+    default: '村落概况',
+  },
+  desc: {
+    type: String,
+    default: '探索村落的历史渊源与发生轨迹',
+  },
+  button: {
+    type: Boolean,
+    default: true,
+  },
+})
+</script>
+
+<template>
+  <FlexRow :padding="25" backgroundColor="white" :radius="20" justify="space-between" align="center">
+    <FlexRow align="center">
+      <FlexCol center radius="50%" backgroundColor="#efefef" :padding="20">
+        <Icon :icon="icon" color="primary" type="material" :size="50" />
+      </FlexCol>
+      <Width :width="20" />
+      <FlexCol class="info">
+        <Text class="title" :fontSize="36" color="text.title" :text="title" />
+        <Height :height="10" />
+        <Text class="desc" :fontSize="24" color="text.second" :text="desc" />
+      </FlexCol>
+    </FlexRow>
+    <Button v-if="button" type="primary" shape="round" size="small" :radius="40" @click="$emit('click')">去完成</Button>
+    <view v-else></view>
+  </FlexRow>
+</template>

+ 104 - 238
src/pages/dig/details.vue

@@ -1,25 +1,30 @@
 <template>
-  <view class="main">
-    <view class="img-banner">
-      <image mode="aspectFill" src="https://mn.wenlvti.net/app_static/xiangan/banner_dig_1.jpg"></image>
-    </view>
-    <view class="level-info">
-      <view>
-        <view class="label">已认领:</view>
-        <view class="value">{{ querys.name }}
-          <text class="em">Lv.{{ querys.level }}</text>
-        </view>
-      </view>
-      <view>
-        <view class="label">文化积分:</view>
-        <view class="value">{{ querys.points }}</view>
-      </view>
-    </view>
+  <FlexCol :padding="30" :gap="20">
+    <Image
+      src="https://mn.wenlvti.net/app_static/xiangan/banner_dig_1.jpg" 
+      :radius="20"
+      round
+      mode="widthFix"
+      :width="690" 
+    />
+    <FlexRow align="center" :gap="10" backgroundColor="white" :padding="20" :radius="20">
+      <FlexRow flexBasis="50%">
+        <Text :fontSize="30" text="已认领:" />
+        <Width :width="20" />
+        <Text :fontSize="30" color="primary" :text="querys.name" />
+      </FlexRow>
+      <FlexRow flexBasis="50%" align="center">
+        <Text :fontSize="30" color="text.content" :text="`文化积分: `" />
+        <Text :fontSize="40" fontFamily="Rockwell" color="primary" :text="querys.points" />
+        <Width :width="20" />
+        <Text :fontSize="40" fontFamily="Rockwell" color="primary" :text="`Lv.${querys.level}`" />
+      </FlexRow>
+    </FlexRow>
+
     <Touchable 
       direction="column" 
       touchable 
       :radius="20"
-      :margin="[30,0]"
       :padding="30"
       align="center"
       backgroundColor="background.primary"
@@ -29,115 +34,83 @@
       <Height :height="20" />
       <Text :fontSize="34">写随手记</Text>
       <Text :fontSize="22" color="gray">写随手记,记录下村庄文化发现和思考,自动分类</Text>
+      <Text :fontSize="22" color="gray">也可点击下方进入指定的分类采集信息</Text>
     </Touchable>
-    <view class="task-list">
-      <view v-if="canCollect('village')" class="item">
-        <text class="iconfont icon-task-summary"></text>
-        <view class="info">
-          <view class="title">村落概况</view>
-          <view class="desc">探索村落的历史渊源与发生轨迹</view>
-        </view>
-        <view class="btn" @click="navTo('task/summary', nextPageData)">去完成</view>
-      </view>
-      <view v-if="canCollect('cultural')" class="item">
-        <text class="iconfont icon-task-history"></text>
-        <view class="info">
-          <view class="title">历史文化</view>
-          <view class="desc">传承百年文化遗产和精神财富</view>
-        </view>
-        <view class="btn" @click="navTo('task/history', nextPageData)">
-          去完成
-        </view>
-      </view>
-      <view v-if="canCollect('ich')" class="item">
-        <text class="iconfont icon-task-custom-1"></text>
-        <view class="info">
-          <view class="title">非物质文化遗产项目</view>
-          <view class="desc">维护文化多样性</view>
-        </view>
-        <view class="btn" @click="goForm('ich', 0, '非物质文化遗产项目')">
-          去完成
-        </view>
-      </view>
-      <view v-if="canCollect('building')" class="item">
-        <text class="iconfont icon-task-environment"></text>
-        <view class="info">
-          <view class="title">环境格局</view>
-          <view class="desc">感受自然人文环境之美</view>
-        </view>
-        <view class="btn" @click="navTo('task/environment', nextPageData)">
-          去完成
-        </view>
-      </view>
-      <view v-if="canCollect('building')" class="item">
-        <text class="iconfont icon-task-building"></text>
-        <view class="info">
-          <view class="title">传统建筑</view>
-          <view class="desc">领略古建筑的独特魅力</view>
-        </view>
-        <view class="btn" @click="navTo('task/building', nextPageData)">
-          去完成
-        </view>
-      </view>
-      <view v-if="canCollect('folk_culture')" class="item">
-        <text class="iconfont icon-task-custom"></text>
-        <view class="info">
-          <view class="title">民俗文化</view>
-          <view class="desc">体验民间传统习俗与节庆</view>
-        </view>
-        <view class="btn" @click="navTo('task/custom', nextPageData)">
-          去完成
-        </view>
-      </view>
-      <view v-if="canCollect('food_product')" class="item">
-        <text class="iconfont icon-task-food"></text>
-        <view class="info">
-          <view class="title">地道美食</view>
-          <view class="desc">正宗、传统地方特色美食</view>
-        </view>
-        <view class="btn" @click="navTo('task/food', nextPageData)">
-          去完成
-        </view>
-      </view>
-      <view v-if="canCollect('food_product')" class="item">
-        <text class="iconfont icon-task-mine"></text>
-        <view class="info">
-          <view class="title">物产资源</view>
-          <view class="desc">特定地域的植物、矿物或手工艺</view>
-        </view>
-        <view class="btn" @click="navTo('task/mine', nextPageData)">
-          去完成
-        </view>
-      </view>
-      <view v-if="canCollect('route')" class="item">
-        <text class="iconfont icon-task-trip"></text>
-        <view class="info">
-          <view class="title">旅游路线</view>
-          <view class="desc">体验独特的文化魅力</view>
-        </view>
-        <view class="btn" @click="navTo('task/trip', nextPageData)">
-          去完成
-        </view>
-      </view>
-      <div v-if="!authStore.isAdmin && isEmpty" class="item">
-        <i class="iconfont icon-task-summary"></i>
-        <div class="info">
-          <div class="title">您当前没有可完成的任务</div>
-          <div class="desc">请联系管理员认领可采编栏目</div>
-        </div>
-      </div>
-      <view class="item">
-        <text class="iconfont icon-task-other"></text>
-        <view class="info">
-          <view class="title">其他</view>
-          <view class="desc">更多文化传承相关信息</view>
-        </view>
-        <view class="btn active">
-          待开放
-        </view>
-      </view>
-    </view>
-  </view>
+
+    <FlexCol :gap="20">
+      <TaskList
+        v-if="canCollect('village')"
+        icon="icon-task-summary"
+        title="村落概况"
+        desc="探索村落的历史渊源与发生轨迹"
+        @click="navTo('task/summary', nextPageData)"
+      />
+      <TaskList
+        v-if="canCollect('cultural')"
+        icon="icon-task-history"
+        title="历史文化"
+        desc="传承百年文化遗产和精神财富"
+        @click="navTo('task/history', nextPageData)"
+      />
+      <TaskList
+        v-if="canCollect('ich')"
+        icon="icon-task-custom-1"
+        title="非物质文化遗产项目"
+        desc="维护文化多样性"
+        @click="goForm('ich', 0, '非物质文化遗产项目')"
+      />
+      <TaskList
+        v-if="canCollect('building')"
+        icon="icon-task-environment"
+        title="环境格局"
+        desc="感受自然人文环境之美"
+        @click="navTo('task/environment', nextPageData)"
+      />
+      <TaskList
+        v-if="canCollect('building')"
+        icon="icon-task-building"
+        title="传统建筑"
+        desc="领略古建筑的独特魅力"
+        @click="navTo('task/building', nextPageData)"
+      />
+      <TaskList
+        v-if="canCollect('folk_culture')"
+        icon="icon-task-custom"
+        title="民俗文化"
+        desc="体验民间传统习俗与节庆"
+        @click="navTo('task/custom', nextPageData)"
+      />
+      <TaskList
+        v-if="canCollect('food_product')"
+        icon="icon-task-food"
+        title="地道美食"
+        desc="正宗、传统地方特色美食"
+        @click="navTo('task/food', nextPageData)"
+      />
+      <TaskList
+        v-if="canCollect('food_product')"
+        icon="icon-task-mine"
+        title="物产资源"
+        desc="特定地域的植物、矿物或手工艺"
+        @click="navTo('task/mine', nextPageData)"
+      />
+      <TaskList
+        v-if="canCollect('route')"
+        icon="icon-task-trip"
+        title="旅游路线"
+        desc="体验独特的文化魅力"
+        @click="navTo('task/trip', nextPageData)"
+      />
+      <TaskList
+        v-if="!authStore.isAdmin && isEmpty"
+        icon="icon-task-summary"
+        title="您当前没有可完成的任务"
+        desc="请联系管理员认领可采编栏目"
+        :button="false"
+      />
+    </FlexCol>
+    <XBarSpace />
+  </FlexCol>
 </template>
 
 <script setup lang="ts">
@@ -146,11 +119,16 @@ import { computed } from 'vue';
 import { useAuthStore } from '@/store/auth';
 import { useCollectStore } from '@/store/collect';
 import { navTo } from '@/components/utils/PageAction';
-import FlexCol from '@/components/layout/FlexCol.vue';
 import Icon from '@/components/basic/Icon.vue';
 import Text from '@/components/basic/Text.vue';
 import Touchable from '@/components/feedback/Touchable.vue';
 import Height from '@/components/layout/space/Height.vue';
+import FlexCol from '@/components/layout/FlexCol.vue';
+import Image from '@/components/basic/Image.vue';
+import FlexRow from '@/components/layout/FlexRow.vue';
+import TaskList from './components/TaskList.vue';
+import XBarSpace from '@/components/layout/space/XBarSpace.vue';
+import Width from '@/components/layout/space/Width.vue';
 
 const { querys } = useLoadQuerys({ 
   id: 0,  
@@ -178,115 +156,3 @@ function goForm(subType: string, subId: number, title: string) {
   })
 }
 </script>
-
-<style lang="scss" scoped>
-.img-banner {
-  height: 246rpx;
-  width: 100%;
-
-  image {
-    height: 100%;
-    width: 100%;
-  }
-}
-
-.level-info {
-  padding: 48rpx 36rpx 36rpx;
-  background: #FFF2E6;
-  border-radius: 20rpx;
-  position: relative;
-  margin-top: 42rpx;
-  margin-bottom: 37rpx;
-  > view:first-child {
-    margin-bottom: 44rpx;
-  }
-
-  .label {
-    font-size: 28rpx;
-    color: #111111;
-    display: inline-block;
-  }
-
-  .value {
-    font-weight: bold;
-    font-size: 28rpx;
-    display: inline-block;
-    color: #333333;
-
-    .em {
-      font-family: Rockwell;
-      font-weight: 600;
-      font-size: 30rpx;
-      color: #FF8719;
-      display: inline-block;
-      margin-left: 35rpx;
-    }
-  }
-
-  .btn {
-    position: absolute;
-    top: 30rpx;
-    right: 30rpx;
-    border-radius: 10rpx;
-    border: 1px solid #FF8719;
-    padding: 15rpx 20rpx;
-    display: flex;
-    align-items: center;
-    font-weight: 400;
-    font-size: 28rpx;
-    color: #FF8719;
-
-    text.iconfont {
-      display: inline-block;
-      margin-right: 15rpx;
-      font-size: 40rpx;
-    }
-  }
-}
-.task-list{
-  .item{
-    display: flex;
-    align-items: center;
-    background: #fff;
-    margin-bottom: 36rpx;
-    padding:39rpx 27rpx 38rpx;
-    text.iconfont{
-      width: 91rpx;
-      height: 91rpx;
-      border-radius: 50%;
-      border: 1px solid #25515E;
-      text-align: center;
-      color: #25515E;
-      font-size: 60rpx;
-      line-height: 91rpx;
-      display: inline-block;
-      margin-right: 17rpx;
-    }
-    .btn{
-      background: #FF8719;
-      border-radius: 28rpx;
-      color:#fff;
-      font-size: 28rpx;
-      padding:14rpx 24rpx;
-      &.active{
-        background: #EFEFEF;
-        color:#999999;
-      }
-    }
-    .info{
-      flex:1;
-      .title{
-        font-weight: 600;
-        font-size: 30rpx;
-        color: #333333;
-        margin-bottom: 22rpx;
-      }
-      .desc{
-        font-weight: 400;
-        font-size: 24rpx;
-        color: #999999;
-      }
-    }
-  }
-}
-</style>

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

@@ -1,5 +1,5 @@
 <template>
-  <CommonRoot class="main">
+  <CommonRoot>
     <LoadingPage v-if="loading" /> 
     <FlexCol :padding="30">
       <DynamicForm
@@ -18,6 +18,7 @@
       <Height :height="20" />
       <Button type="primary" @click="submit">提交</Button>
     </FlexCol>
+    <XBarSpace />
   </CommonRoot>
 </template>
 
@@ -36,6 +37,7 @@ import FlexCol from '@/components/layout/FlexCol.vue';
 import type { FormDefine, FormExport } from '@/components/dynamic';
 import Height from '@/components/layout/space/Height.vue';
 import { backAndCallOnPageBack } from '@/components/utils/PageAction';
+import XBarSpace from '@/components/layout/space/XBarSpace.vue';
 
 const loading = ref(false);
 const subTitle = ref('');

+ 2 - 0
src/pages/dig/forms/list.vue

@@ -43,6 +43,7 @@
         </Empty>
       </template>
     </SimplePageListLoader>
+    <XBarSpace />
   </FlexCol>
 </template>
 
@@ -64,6 +65,7 @@ import { navTo } from '@/components/utils/PageAction';
 import Height from '@/components/layout/space/Height.vue';
 import H4 from '@/components/typography/H4.vue';
 import Touchable from '@/components/feedback/Touchable.vue';
+import XBarSpace from '@/components/layout/space/XBarSpace.vue';
 
 const subTitle = ref('');
 const searchText = ref('');

+ 18 - 20
src/pages/dig/index.vue

@@ -1,11 +1,11 @@
 <template>
-  <view class="submit_main">
+  <FlexCol>
     <Image 
       mode="aspectFill" 
       src="https://mn.wenlvti.net/app_static/xiangan/banner_submit.jpg"
       width="100%"
     />
-    <view class="main">
+    <FlexCol :padding="30">
       <SubTitle title="我的村庄" />
       <RequireLogin unLoginMessage="登录后查看我认领的村庄">
         <SimplePageContentLoader
@@ -25,24 +25,22 @@
               backgroundColor="white"
               :radius="20"
               :padding="20"
+              justify="space-between"
             >
-              <Image 
-                mode="aspectFill"
-                :src="item.image" 
-                :radius="20"
-                round
-                :width="130"
-                :height="130"
-              />
-              <Width :size="20" />
-              <FlexCol>
+              <FlexRow align="center" :gap="20">
+                <Image 
+                  mode="aspectFill"
+                  :src="item.image" 
+                  round
+                  :width="80"
+                  :height="80"
+                />
                 <H3>{{ item.villageName }}</H3>
-                <Height :size="10" />
-                <FlexRow align="center" :flex="1" :gap="10">
-                  <Button type="primary" size="large" icon="work-filling" @click="goManagePage(item)">管理</Button>
-                  <Button type="default" size="large" icon="edit-filling" @click="goSubmitDigPage(item)">采编</Button>
-                </FlexRow>
-              </FlexCol>
+              </FlexRow>
+              <FlexRow align="center" :gap="20">
+                <Button type="primary" size="small" icon="work-filling" @click="goManagePage(item)">管理</Button>
+                <Button type="default" size="small" icon="edit-filling" @click="goSubmitDigPage(item)">采编</Button>
+              </FlexRow>
             </FlexRow>
           </FlexCol>
         </SimplePageContentLoader>
@@ -61,8 +59,8 @@
           </FlexCol>
         </FlexRow>
       </RequireLogin>
-    </view>
-  </view>
+    </FlexCol>
+  </FlexCol>
 </template>
 
 <script setup lang="ts">

+ 38 - 47
src/pages/dig/task/building.vue

@@ -1,56 +1,47 @@
 <template>
-  <view class="main">
-    <view class="img-banner">
-      <image mode="aspectFill" src="https://mn.wenlvti.net/app_static/xiangan/banner_dig_building.jpg"></image>
-    </view>
-    <view class="task-list">
-      <view v-if="canCollect('distribution')" class="item">
-        <text class="iconfont icon-task-building-1"></text>
-        <view class="info">
-          <view class="title">建筑分布</view>
-          <view class="desc">村落内传统建筑分布情况</view>
-        </view>
-        <view class="btn" @click="goForm('distribution', 0, undefined, undefined, '建筑分布')">
-          填写
-        </view>
-      </view>
-      <view class="item">
-        <text class="iconfont icon-task-building-2"></text>
-        <view class="info">
-          <view class="title">文物建筑</view>
-          <view class="desc">历史、艺术、科学价值</view>
-        </view>
-        <view class="btn" @click="goForm('building', 1, 'nature', undefined, '文物建筑')">
-          填写
-        </view>
-      </view>
-      <view class="item">
-        <text class="iconfont icon-task-building-3"></text>
-        <view class="info">
-          <view class="title">历史建筑</view>
-          <view class="desc">重大历史事件记录</view>
-        </view>
-        <view class="btn" @click="goForm('building', 2, 'nature', undefined, '历史建筑')">
-          填写
-        </view>
-      </view>
-      <view class="item">
-        <text class="iconfont icon-task-building-4"></text>
-        <view class="info">
-          <view class="title">重要传统建筑</view>
-          <view class="desc">重要传统建筑的信息</view>
-        </view>
-        <view class="btn" @click="goForm('building', 3, 'nature', undefined, '重要传统建筑')">
-          填写
-        </view>
-      </view>
-    </view>
-  </view>
+  <FlexCol :padding="30" :gap="10">
+    <Image
+      src="https://mn.wenlvti.net/app_static/xiangan/banner_dig_building.jpg"
+      :radius="20"
+      mode="widthFix"
+      :width="690"
+    />
+    <FlexCol :gap="20">
+      <TaskList
+        v-if="canCollect('distribution')"
+        icon="icon-task-building-1"
+        title="建筑分布"
+        desc="村落内传统建筑分布情况"
+        @click="goForm('distribution', 0, undefined, undefined, '建筑分布')"
+      />
+      <TaskList
+        icon="icon-task-building-2"
+        title="文物建筑"
+        desc="历史、艺术、科学价值"
+        @click="goForm('building', 1, 'nature', undefined, '文物建筑')"
+      />
+      <TaskList
+        icon="icon-task-building-3"
+        title="历史建筑"
+        desc="重大历史事件记录"
+        @click="goForm('building', 2, 'nature', undefined, '历史建筑')"
+      />
+      <TaskList
+        icon="icon-task-building-4"
+        title="重要传统建筑"
+        desc="重要传统建筑的信息"
+        @click="goForm('building', 3, 'nature', undefined, '重要传统建筑')"
+      />
+    </FlexCol>
+  </FlexCol>
 </template>
 
 <script setup lang="ts">
 import { useCollectStore } from '@/store/collect';
 import { useTaskEntryForm } from '../composeable/TaskEntryForm';
+import FlexCol from '@/components/layout/FlexCol.vue';
+import Image from '@/components/basic/Image.vue';
+import TaskList from '../components/TaskList.vue';
 
 const { goForm } = useTaskEntryForm();
 const { canCollect } = useCollectStore();

+ 49 - 67
src/pages/dig/task/custom.vue

@@ -1,76 +1,58 @@
 <template>
-  <view class="main">
-    <view class="img-banner">
-      <image mode="aspectFill" src="https://mn.wenlvti.net/app_static/xiangan/banner_dig_custom.png"></image>
-    </view>
-    <view class="task-list">
-      <view class="item">
-        <text class="iconfont icon-task-custom-1"></text>
-        <view class="info">
-          <view class="title">非物质文化遗产项目</view>
-          <view class="desc">维护文化多样性</view>
-        </view>
-        <view class="btn" @click="goForm('ich', 0, undefined, undefined, '非物质文化遗产项目')">
-          填写
-        </view>
-      </view>
-      <view class="item">
-        <text class="iconfont icon-task-custom-2"></text>
-        <view class="info">
-          <view class="title">节庆活动</view>
-          <view class="desc">欢庆与传承并重的文化盛宴</view>
-        </view>
-        <view class="btn" @click="goForm('folk_culture', 1, 'folk_culture_type', undefined, '节庆活动')">
-          填写
-        </view>
-      </view>
-      <view class="item">
-        <text class="iconfont icon-task-custom-3"></text>
-        <view class="info">
-          <view class="title">祭祀崇礼</view>
-          <view class="desc">对先贤与自然的崇高致敬</view>
-        </view>
-        <view class="btn" @click="goForm('folk_culture', 2, 'folk_culture_type', undefined, '祭祀崇礼')">
-          填写
-        </view>
-      </view>
-      <view class="item">
-        <text class="iconfont icon-task-custom-4"></text>
-        <view class="info">
-          <view class="title">婚丧嫁娶</view>
-          <view class="desc">生命礼赞与文化传承的双重奏鸣</view>
-        </view>
-        <view class="btn" @click="goForm('folk_culture', 3, 'folk_culture_type', undefined, '婚丧嫁娶')">
-          填写
-        </view>
-      </view>
-      <view class="item">
-        <text class="iconfont icon-task-custom-5"></text>
-        <view class="info">
-          <view class="title">地方方言</view>
-          <view class="desc">历史沉淀的语言瑰宝</view>
-        </view>
-        <view class="btn" @click="goForm('folk_culture', 4, 'folk_culture_type', undefined, '地方方言')">
-          填写
-        </view>
-      </view>
-      <view class="item">
-        <text class="iconfont icon-task-custom-6"></text>
-        <view class="info">
-          <view class="title">特色文化</view>
-          <view class="desc">民族精神的鲜明烙印</view>
-        </view>
-        <view class="btn" @click="goForm('folk_culture', 5, 'folk_culture_type', undefined, '特色文化')">
-          填写
-        </view>
-      </view>
-    </view>
-  </view>
+  <FlexCol :padding="30" :gap="10">
+    <Image
+      src="https://mn.wenlvti.net/app_static/xiangan/banner_dig_custom.png"
+      :radius="20"
+      mode="widthFix"
+      :width="690"
+    />
+    <FlexCol :gap="20">
+      <TaskList
+        icon="icon-task-custom-1"
+        title="非物质文化遗产项目"
+        desc="维护文化多样性"
+        @click="goForm('ich', 0, undefined, undefined, '非物质文化遗产项目')"
+      />
+      <TaskList
+        icon="icon-task-custom-2"
+        title="节庆活动"
+        desc="欢庆与传承并重的文化盛宴"
+        @click="goForm('folk_culture', 1, 'folk_culture_type', undefined, '节庆活动')"
+      />
+      <TaskList
+        icon="icon-task-custom-3"
+        title="祭祀崇礼"
+        desc="对先贤与自然的崇高致敬"
+        @click="goForm('folk_culture', 2, 'folk_culture_type', undefined, '祭祀崇礼')"
+      />
+      <TaskList
+        icon="icon-task-custom-4"
+        title="婚丧嫁娶"
+        desc="生命礼赞与文化传承的双重奏鸣"
+        @click="goForm('folk_culture', 3, 'folk_culture_type', undefined, '婚丧嫁娶')"
+      />
+      <TaskList
+        icon="icon-task-custom-5"
+        title="地方方言"
+        desc="历史沉淀的语言瑰宝"
+        @click="goForm('folk_culture', 4, 'folk_culture_type', undefined, '地方方言')"
+      />
+      <TaskList
+        icon="icon-task-custom-6"
+        title="特色文化"
+        desc="民族精神的鲜明烙印"
+        @click="goForm('folk_culture', 5, 'folk_culture_type', undefined, '特色文化')"
+      />
+    </FlexCol>
+  </FlexCol>
 </template>
 
 <script setup lang="ts">
 import { useCollectStore } from '@/store/collect';
 import { useTaskEntryForm } from '../composeable/TaskEntryForm';
+import FlexCol from '@/components/layout/FlexCol.vue';
+import Image from '@/components/basic/Image.vue';
+import TaskList from '../components/TaskList.vue';
 
 const { goForm } = useTaskEntryForm();
 const { canCollect } = useCollectStore();

+ 35 - 37
src/pages/dig/task/environment.vue

@@ -1,46 +1,44 @@
 <template>
-  <view class="main">
-    <view class="img-banner">
-      <image mode="aspectFill" src="https://mn.wenlvti.net/app_static/xiangan/banner_dig_environment.jpg"></image>
-    </view>
-    <view class="task-list">
-      <view class="item">
-        <text class="iconfont icon-task-environment-1"></text>
-        <view class="info">
-          <view class="title">自然环境</view>
-          <view class="desc">村落建立与发展历程</view>
-        </view>
-        <view class="btn" @click="goForm('environment', 0, undefined, undefined, '自然环境')">
-          填写
-        </view>
-      </view>
-      <view v-if="canCollect('cultural_relic')" class="item">
-        <text class="iconfont icon-task-environment-5"></text>
-        <view class="info">
-          <view class="title">文物古迹</view>
-          <view class="desc">重要历史文献资料</view>
-        </view>
-        <view class="btn" @click="goForm('relic', 0, undefined, undefined, '文物古迹')">
-          填写
-        </view>
-      </view>
-      <view v-if="canCollect('element')" class="item">
-        <text class="iconfont icon-task-environment-6"></text>
-        <view class="info">
-          <view class="title">历史环境要素</view>
-          <view class="desc">村民口述历史记录</view>
-        </view>
-        <view class="btn" @click="goForm('element', 0, undefined, undefined, '历史环境要素')">
-          填写
-        </view>
-      </view>
-    </view>
-  </view>
+  <FlexCol :padding="30" :gap="20">
+    <Image
+      src="https://mn.wenlvti.net/app_static/xiangan/banner_dig_environment.jpg"
+      :radius="20"
+      mode="widthFix"
+      :width="690"
+    />
+    <FlexCol :gap="20">
+      <TaskList
+        icon="icon-task-environment-1"
+        title="自然环境"
+        desc="村落建立与发展历程"
+        @click="goForm('environment', 0, undefined, undefined, '自然环境')"
+      />
+      <TaskList
+        v-if="canCollect('cultural_relic')"
+        icon="icon-task-environment-5"
+        title="文物古迹"
+        desc="重要历史文献资料"
+        @click="goForm('relic', 0, undefined, undefined, '文物古迹')"
+      />
+      <TaskList
+        v-if="canCollect('element')"
+        icon="icon-task-environment-6"
+        title="历史环境要素"
+        desc="村民口述历史记录"
+        @click="goForm('element', 0, undefined, undefined, '历史环境要素')"
+      />
+    </FlexCol>
+    <XBarSpace />
+  </FlexCol>
 </template>
 
 <script setup lang="ts">
 import { useCollectStore } from '@/store/collect';
 import { useTaskEntryForm } from '../composeable/TaskEntryForm';
+import FlexCol from '@/components/layout/FlexCol.vue';
+import Image from '@/components/basic/Image.vue';
+import TaskList from '../components/TaskList.vue';
+import XBarSpace from '@/components/layout/space/XBarSpace.vue';
 
 const { goForm } = useTaskEntryForm();
 const { canCollect } = useCollectStore();

+ 26 - 27
src/pages/dig/task/food.vue

@@ -1,36 +1,35 @@
 <template>
-  <view class="main">
-    <view class="img-banner">
-      <image mode="aspectFill" src="https://mn.wenlvti.net/app_static/xiangan/banner_dig_food.jpg"></image>
-    </view>
-    <view class="task-list">
-      <view class="item">
-        <text class="iconfont icon-task-food-1"></text>
-        <view class="info">
-          <view class="title">农副产品</view>
-          <view class="desc">乡村繁荣的多元支柱</view>
-        </view>
-        <view class="btn" @click="goForm('food_product', 1, undefined, undefined, '农副产品')">
-          填写
-        </view>
-      </view>
-      <view class="item">
-        <text class="iconfont icon-task-food-2"></text>
-        <view class="info">
-          <view class="title">特色美食</view>
-          <view class="desc">给味蕾探索带来无限惊喜</view>
-        </view>
-        <view class="btn" @click="goForm('food_product', 3, undefined, undefined, '特色美食')">
-          填写
-        </view>
-      </view>
-    </view>
-  </view>
+  <FlexCol :padding="30" :gap="20">
+    <Image
+      src="https://mn.wenlvti.net/app_static/xiangan/banner_dig_food.jpg"
+      :radius="20"
+      round
+      mode="widthFix"
+      :width="690"
+    />
+    <FlexCol :gap="20">
+      <TaskList
+        icon="icon-task-food-1"
+        title="农副产品"
+        desc="乡村繁荣的多元支柱"
+        @click="goForm('food_product', 1, undefined, undefined, '农副产品')"
+      />
+      <TaskList
+        icon="icon-task-food-2"
+        title="特色美食"
+        desc="给味蕾探索带来无限惊喜"
+        @click="goForm('food_product', 3, undefined, undefined, '特色美食')"
+      />
+    </FlexCol>
+  </FlexCol>
 </template>
 
 <script setup lang="ts">
 import { useCollectStore } from '@/store/collect';
 import { useTaskEntryForm } from '../composeable/TaskEntryForm';
+import FlexCol from '@/components/layout/FlexCol.vue';
+import Image from '@/components/basic/Image.vue';
+import TaskList from '../components/TaskList.vue';
 
 const { canCollect } = useCollectStore();
 const { goForm } = useTaskEntryForm();

+ 51 - 67
src/pages/dig/task/history.vue

@@ -1,76 +1,60 @@
 <template>
-  <view class="main">
-    <view class="img-banner">
-      <image mode="aspectFill" src="https://mn.wenlvti.net/app_static/xiangan/banner_dig_history.jpg"></image>
-    </view>
-    <view class="task-list">
-      <view class="item">
-        <text class="iconfont icon-task-history-1"></text>
-        <view class="info">
-          <view class="title">建村历史</view>
-          <view class="desc">村落建立与发展历程</view>
-        </view>
-        <view class="btn" @click="goForm('cultural', 1, undefined, undefined, '建村历史')">
-          填写
-        </view>
-      </view>
-      <view class="item">
-        <text class="iconfont icon-task-history-2"></text>
-        <view class="info">
-          <view class="title">历史人物</view>
-          <view class="desc">重要历史人物事迹</view>
-        </view>
-        <view class="btn" @click="goForm('figure', 0, undefined, undefined, '历史人物')">
-          填写
-        </view>
-      </view>
-      <view class="item">
-        <text class="iconfont icon-task-history-3"></text>
-        <view class="info">
-          <view class="title">历史事件</view>
-          <view class="desc">重大历史事件记录</view>
-        </view>
-        <view class="btn" @click="goForm('cultural', 2, undefined, undefined, '历史事件')">
-          填写
-        </view>
-      </view>
-      <view v-if="canCollect('story')" class="item">
-        <text class="iconfont icon-task-history-4"></text>
-        <view class="info">
-          <view class="title">掌故轶事</view>
-          <view class="desc">民间传说与历史故事</view>
-        </view>
-        <view class="btn" @click="goForm('story', 0, undefined, undefined, '掌故轶事')">
-          填写
-        </view>
-      </view>
-      <view class="item">
-        <text class="iconfont icon-task-history-5"></text>
-        <view class="info">
-          <view class="title">历史文献</view>
-          <view class="desc">重要历史文献资料</view>
-        </view>
-        <view class="btn" @click="goForm('cultural', 3, undefined, undefined, '历史文献')">
-          填写
-        </view>
-      </view>
-      <view class="item">
-        <text class="iconfont icon-task-history-6"></text>
-        <view class="info">
-          <view class="title">口述历史</view>
-          <view class="desc">村民口述历史记录</view>
-        </view>
-        <view class="btn" @click="goForm('cultural', 4, undefined, undefined, '口述历史')">
-          填写
-        </view>
-      </view>
-    </view>
-  </view>
+  <FlexCol :padding="30" :gap="20">
+    <Image
+      src="https://mn.wenlvti.net/app_static/xiangan/banner_dig_history.jpg"
+      :radius="20"
+      round
+      mode="widthFix"
+      :width="690"
+    />
+    <FlexCol :gap="20">
+      <TaskList
+        icon="icon-task-history-1"
+        title="建村历史"
+        desc="村落建立与发展历程"
+        @click="goForm('cultural', 1, undefined, undefined, '建村历史')"
+      />
+      <TaskList
+        icon="icon-task-history-2"
+        title="历史人物"
+        desc="重要历史人物事迹"
+        @click="goForm('figure', 0, undefined, undefined, '历史人物')"
+      />
+      <TaskList
+        icon="icon-task-history-3"
+        title="历史事件"
+        desc="重大历史事件记录"
+        @click="goForm('cultural', 2, undefined, undefined, '历史事件')"
+      />
+      <TaskList
+        v-if="canCollect('story')"
+        icon="icon-task-history-4"
+        title="掌故轶事"
+        desc="民间传说与历史故事"
+        @click="goForm('story', 0, undefined, undefined, '掌故轶事')"
+      />
+      <TaskList
+        icon="icon-task-history-5"
+        title="历史文献"
+        desc="重要历史文献资料"
+        @click="goForm('cultural', 3, undefined, undefined, '历史文献')"
+      />
+      <TaskList
+        icon="icon-task-history-6"
+        title="口述历史"
+        desc="村民口述历史记录"
+        @click="goForm('cultural', 4, undefined, undefined, '口述历史')"
+      />
+    </FlexCol>
+  </FlexCol>
 </template>
 
 <script setup lang="ts">
 import { useCollectStore } from '@/store/collect';
 import { useTaskEntryForm } from '../composeable/TaskEntryForm';
+import FlexCol from '@/components/layout/FlexCol.vue';
+import Image from '@/components/basic/Image.vue';
+import TaskList from '../components/TaskList.vue';
 
 const { canCollect } = useCollectStore();
 const { goForm } = useTaskEntryForm();

+ 32 - 37
src/pages/dig/task/mine.vue

@@ -1,46 +1,41 @@
 <template>
-  <view class="main">
-    <view class="img-banner">
-      <image mode="aspectFill" src="https://mn.wenlvti.net/app_static/xiangan/banner_dig_mine.jpg"></image>
-    </view>
-    <view class="task-list">
-      <view class="item">
-        <text class="iconfont icon-task-mine-1"></text>
-        <view class="info">
-          <view class="title">商业集市</view>
-          <view class="desc">文化交流的开放窗口</view>
-        </view>
-        <view class="btn" @click="goForm('food_product', 4, undefined, undefined, '商业集市')">
-          填写
-        </view>
-      </view>
-      <view class="item">
-        <text class="iconfont icon-task-mine-2"></text>
-        <view class="info">
-          <view class="title">服装服饰</view>
-          <view class="desc">艺术与功能交织的时尚篇章</view>
-        </view>
-        <view class="btn" @click="goForm('food_product', 5, undefined, undefined, '服装服饰')">
-          填写
-        </view>
-      </view>
-      <view class="item">
-        <text class="iconfont icon-task-mine-2"></text>
-        <view class="info">
-          <view class="title">运输工具</view>
-          <view class="desc">历史的运输工具</view>
-        </view>
-        <view class="btn" @click="goForm('food_product', 6, undefined, undefined, '运输工具')">
-          填写
-        </view>
-      </view>
-    </view>
-  </view>
+  <FlexCol :padding="30" :gap="20">
+    <Image
+      src="https://mn.wenlvti.net/app_static/xiangan/banner_dig_mine.jpg"
+      :radius="20"
+      round
+      mode="widthFix"
+      :width="690"
+    />
+    <FlexCol :gap="20">
+      <TaskList
+        icon="icon-task-mine-1"
+        title="商业集市"
+        desc="文化交流的开放窗口"
+        @click="goForm('food_product', 4, undefined, undefined, '商业集市')"
+      />
+      <TaskList
+        icon="icon-task-mine-2"
+        title="服装服饰"
+        desc="艺术与功能交织的时尚篇章"
+        @click="goForm('food_product', 5, undefined, undefined, '服装服饰')"
+      />
+      <TaskList
+        icon="icon-task-mine-2"
+        title="运输工具"
+        desc="历史的运输工具"
+        @click="goForm('food_product', 6, undefined, undefined, '运输工具')"
+      />
+    </FlexCol>
+  </FlexCol>
 </template>
 
 <script setup lang="ts">
 import { useCollectStore } from '@/store/collect';
 import { useTaskEntryForm } from '../composeable/TaskEntryForm';
+import FlexCol from '@/components/layout/FlexCol.vue';
+import Image from '@/components/basic/Image.vue';
+import TaskList from '../components/TaskList.vue';
 
 const { canCollect } = useCollectStore();
 const { goForm } = useTaskEntryForm();

+ 46 - 57
src/pages/dig/task/summary.vue

@@ -1,66 +1,55 @@
 <template>
-  <view class="main">
-    <view class="img-banner">
-      <image mode="aspectFill" src="https://mn.wenlvti.net/app_static/xiangan/banner_dig_summary.jpg"></image>
-    </view>
-    <view class="task-list">
-      <view class="item">
-        <text class="iconfont icon-task-summary-1"></text>
-        <view class="info">
-          <view class="title">行政区划</view>
-          <view class="desc">村落行政区域划分及变迁</view>
-        </view>
-        <view class="btn" @click="goForm(1, '行政区划')">
-          填写
-        </view>
-      </view>
-      <view class="item">
-        <text class="iconfont icon-task-summary-5"></text>
-        <view class="info">
-          <view class="title">村落综述</view>
-          <view class="desc">村落整体概况介绍</view>
-        </view>
-        <view class="btn" @click="goForm(5, '村落综述')">
-          填写
-        </view>
-      </view>
-      <view class="item">
-        <text class="iconfont icon-task-summary-2"></text>
-        <view class="info">
-          <view class="title">地理信息</view>
-          <view class="desc">地理位置和自然环境特征</view>
-        </view>
-        <view class="btn" @click="goForm(2, '地理信息')">
-          填写
-        </view>
-      </view>
-      <view class="item">
-        <text class="iconfont icon-task-summary-3"></text>
-        <view class="info">
-          <view class="title">建设与保护</view>
-          <view class="desc">村落发展与文化遗产保护</view>
-        </view>
-        <view class="btn" @click="goForm(3, '建设与保护')">
-          填写
-        </view>
-      </view>
-      <view class="item">
-        <text class="iconfont icon-task-summary-4"></text>
-        <view class="info">
-          <view class="title">人口与经济</view>
-          <view class="desc">人口与经济情况</view>
-        </view>
-        <view class="btn" @click="goForm(4, '人口与经济')">
-          填写
-        </view>
-      </view>
-    </view>
-  </view>
+  <FlexCol :padding="30" :gap="20">
+    <Image
+      src="https://mn.wenlvti.net/app_static/xiangan/banner_dig_summary.jpg"
+      :radius="20"
+      round
+      mode="widthFix"
+      :width="690"
+    />
+    <FlexCol :gap="20">
+      <TaskList
+        icon="icon-task-summary-1"
+        title="行政区划"
+        desc="村落行政区域划分及变迁"
+        @click="goForm(1, '行政区划')"
+      />
+      <TaskList
+        icon="icon-task-summary-5"
+        title="村落综述"
+        desc="村落整体概况介绍"
+        @click="goForm(5, '村落综述')"
+      />
+      <TaskList
+        icon="icon-task-summary-2"
+        title="地理信息"
+        desc="地理位置和自然环境特征"
+        @click="goForm(2, '地理信息')"
+      />
+      <TaskList
+        icon="icon-task-summary-3"
+        title="建设与保护"
+        desc="村落发展与文化遗产保护"
+        @click="goForm(3, '建设与保护')"
+      />
+      <TaskList
+        icon="icon-task-summary-4"
+        title="人口与经济"
+        desc="人口与经济情况"
+        @click="goForm(4, '人口与经济')"
+      />
+    </FlexCol>
+    <XBarSpace />
+  </FlexCol>
 </template>
 
 <script setup lang="ts">
 import { useCollectStore } from '@/store/collect';
 import { useTaskEntryForm } from '../composeable/TaskEntryForm';
+import FlexCol from '@/components/layout/FlexCol.vue';
+import Image from '@/components/basic/Image.vue';
+import TaskList from '../components/TaskList.vue';
+import XBarSpace from '@/components/layout/space/XBarSpace.vue';
 
 const { canCollect } = useCollectStore();
 const t = useTaskEntryForm();

+ 38 - 53
src/pages/dig/task/trip.vue

@@ -1,63 +1,48 @@
 <template>
-  <view class="main">
-    <view class="img-banner">
-      <image mode="aspectFill" src="https://mn.wenlvti.net/app_static/xiangan/banner_dig_trip.jpg"></image>
-    </view>
-    <view class="task-list">
-      <view v-if="canCollect('travel_guide')" class="item">
-        <text class="iconfont icon-task-trip-3"></text>
-        <view class="info">
-          <view class="title">旅游导览</view>
-        </view>
-        <view class="btn" @click="goForm('travel_guide', 0, undefined, undefined, '旅游导览')">
-          填写
-        </view>
-      </view>
-      <view v-if="canCollect('route')" class="item">
-        <text class="iconfont icon-task-trip-1"></text>
-        <view class="info">
-          <view class="title">游览路线</view>
-        </view>
-        <view class="btn" @click="goForm('route', 1, undefined, undefined, '游览路线')">
-          填写
-        </view>
-      </view>
-      <view class="item">
-        <text class="iconfont icon-task-trip-2"></text>
-        <view class="info">
-          <view class="title">活动时间</view>
-        </view>
-        <view class="btn" @click="goForm('route', 2, undefined, undefined, '活动时间')">
-          填写
-        </view>
-      </view>
-      <view class="item">
-        <text class="iconfont icon-task-trip-4"></text>
-        <view class="info">
-          <view class="title">路线特色</view>
-        </view>
-        <view class="btn" @click="goForm('route', 3, undefined, undefined, '路线特色')">
-          填写
-        </view>
-      </view>
-    </view>
-  </view>
+  <FlexCol :padding="30" :gap="20">
+    <Image
+      src="https://mn.wenlvti.net/app_static/xiangan/banner_dig_trip.jpg"
+      :radius="20"
+      round
+      mode="widthFix"
+      :width="690"
+    />
+    <FlexCol :gap="20">
+      <TaskList
+        v-if="canCollect('travel_guide')"
+        icon="icon-task-trip-3"
+        title="旅游导览"
+        @click="goForm('travel_guide', 0, undefined, undefined, '旅游导览')"
+      />
+      <TaskList
+        v-if="canCollect('route')"
+        icon="icon-task-trip-1"
+        title="游览路线"
+        @click="goForm('route', 1, undefined, undefined, '游览路线')"
+      />
+      <TaskList
+        icon="icon-task-trip-2"
+        title="活动时间"
+        @click="goForm('route', 2, undefined, undefined, '活动时间')"
+      />
+      <TaskList
+        icon="icon-task-trip-4"
+        title="路线特色"
+        @click="goForm('route', 3, undefined, undefined, '路线特色')"
+      />
+    </FlexCol>
+    <XBarSpace />
+  </FlexCol>
 </template>
 
 <script setup lang="ts">
 import { useCollectStore } from '@/store/collect';
 import { useTaskEntryForm } from '../composeable/TaskEntryForm';
+import FlexCol from '@/components/layout/FlexCol.vue';
+import Image from '@/components/basic/Image.vue';
+import TaskList from '../components/TaskList.vue';
+import XBarSpace from '@/components/layout/space/XBarSpace.vue';
 
 const { canCollect } = useCollectStore(); 
 const { goForm } = useTaskEntryForm();
 </script>
-
-<style lang="scss" scoped>
-.task-list {
-  .item{
-    .title{
-      margin-bottom: 0;
-    }
-  }
-}
-</style>

+ 3 - 2
src/pages/user/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="main" style="padding-bottom:50rpx;padding-top:44px;">
+  <FlexCol :padding="[40,30,50,30]">
     <FlexRow align="center">
       <Image 
         :src="userInfo?.avatar || UserHead"
@@ -24,7 +24,7 @@
     <CellGroup v-if="userInfo">
       <Cell icon="https://mn.wenlvti.net/uploads/20250313/cbc47d0b9cad7891e6154359952858c6.png" title="退出登录" showArrow touchable @click="doLogout" />
     </CellGroup>
-  </view>
+  </FlexCol>
 </template>
 
 <script setup lang="ts">
@@ -42,6 +42,7 @@ import Height from '@/components/layout/space/Height.vue';
 import { confirm } from '@/components/utils/DialogAction';
 import { navTo } from '@/components/utils/PageAction';
 import Touchable from '@/components/feedback/Touchable.vue';
+import FlexCol from '@/components/layout/FlexCol.vue';
 
 const authStore = useAuthStore();
 const userInfo = computed(() => authStore.userInfo);