From b61e0dd54ca5adf96bea4fd1f92d498fe5245ff4 Mon Sep 17 00:00:00 2001
From: wupengfei <834520024@qq.com>
Date: 星期五, 14 二月 2025 09:13:27 +0800
Subject: [PATCH] feat: mine

---
 apps/bMiniApp/src/assets/workbenches/icon-person-manage.png          |    0 
 apps/bMiniApp/src/assets/workbenches/icon-publish-task.png           |    0 
 apps/bMiniApp/src/assets/workbenches/icon-task-manage.png            |    0 
 apps/bMiniApp/src/constants/task.ts                                  |   64 +++++
 packages/components/src/Input/ChooseLocationInput.vue                |  103 +++++++++
 apps/bMiniApp/src/constants/router.ts                                |    2 
 apps/bMiniApp/src/pages/workbenches/InnerPage.vue                    |   74 ++++++
 apps/bMiniApp/src/subpackages/task/publishTask/publishTask.vue       |   17 +
 apps/bMiniApp/src/subpackages/task/publishTask/publishTask.config.ts |    3 
 apps/bMiniApp/src/assets/workbenches/icon-flexjob-manage.png         |    0 
 apps/bMiniApp/project.private.config.json                            |   14 +
 packages/components/assets/components/icon-location.png              |    0 
 packages/components/src/Card/TaskDetailWelfareItem.vue               |   13 
 apps/bMiniApp/src/app.config.ts                                      |    6 
 apps/cMiniApp/src/subpackages/task/taskDetail/InnerPage.vue          |   13 
 packages/components/src/index.ts                                     |    2 
 apps/bMiniApp/src/pages/mine/index.vue                               |   58 ++--
 apps/bMiniApp/src/subpackages/task/publishTask/InnerPage.vue         |  209 +++++++++++++++++++
 apps/bMiniApp/src/pages/mine/index.scss                              |   20 -
 apps/bMiniApp/src/components/Chunk/Cell.vue                          |    2 
 packages/components/types/global.d.ts                                |   12 +
 apps/bMiniApp/src/assets/workbenches/icon-accept-manage.png          |    0 
 22 files changed, 546 insertions(+), 66 deletions(-)

diff --git a/apps/bMiniApp/project.private.config.json b/apps/bMiniApp/project.private.config.json
index c8aa3a2..390553f 100644
--- a/apps/bMiniApp/project.private.config.json
+++ b/apps/bMiniApp/project.private.config.json
@@ -14,6 +14,20 @@
                     "query": "",
                     "launchMode": "default",
                     "scene": null
+                },
+                {
+                    "name": "宸ヤ綔鍙�",
+                    "pathName": "pages/workbenches/workbenches",
+                    "query": "",
+                    "launchMode": "default",
+                    "scene": null
+                },
+                {
+                    "name": "鍙戝竷鎷涜仒",
+                    "pathName": "subpackages/task/publishTask/publishTask",
+                    "query": "",
+                    "launchMode": "default",
+                    "scene": null
                 }
             ]
         }
diff --git a/apps/bMiniApp/src/app.config.ts b/apps/bMiniApp/src/app.config.ts
index f6774a8..2a85fdd 100644
--- a/apps/bMiniApp/src/app.config.ts
+++ b/apps/bMiniApp/src/app.config.ts
@@ -1,7 +1,7 @@
 export default defineAppConfig({
   entryPagePath: 'pages/home/index',
   pages: ['pages/home/index', 'pages/mine/index', 'pages/workbenches/workbenches'],
-  requiredPrivateInfos: ['getLocation'],
+  requiredPrivateInfos: ['getLocation', 'chooseLocation'],
   permission: {
     'scope.userLocation': {
       desc: '浣犵殑浣嶇疆淇℃伅灏嗙敤浜庡皬绋嬪簭鏁版嵁鐨勬晥鏋滃睍绀�',
@@ -75,6 +75,10 @@
       ],
     },
     {
+      root: 'subpackages/task',
+      pages: ['publishTask/publishTask'],
+    },
+    {
       root: 'subpackages/city',
       pages: ['citySelect/citySelect'],
     },
diff --git a/apps/bMiniApp/src/assets/workbenches/icon-accept-manage.png b/apps/bMiniApp/src/assets/workbenches/icon-accept-manage.png
new file mode 100644
index 0000000..f2dbef3
--- /dev/null
+++ b/apps/bMiniApp/src/assets/workbenches/icon-accept-manage.png
Binary files differ
diff --git a/apps/bMiniApp/src/assets/workbenches/icon-flexjob-manage.png b/apps/bMiniApp/src/assets/workbenches/icon-flexjob-manage.png
new file mode 100644
index 0000000..d954496
--- /dev/null
+++ b/apps/bMiniApp/src/assets/workbenches/icon-flexjob-manage.png
Binary files differ
diff --git a/apps/bMiniApp/src/assets/workbenches/icon-person-manage.png b/apps/bMiniApp/src/assets/workbenches/icon-person-manage.png
new file mode 100644
index 0000000..ba459e8
--- /dev/null
+++ b/apps/bMiniApp/src/assets/workbenches/icon-person-manage.png
Binary files differ
diff --git a/apps/bMiniApp/src/assets/workbenches/icon-publish-task.png b/apps/bMiniApp/src/assets/workbenches/icon-publish-task.png
new file mode 100644
index 0000000..7ceded4
--- /dev/null
+++ b/apps/bMiniApp/src/assets/workbenches/icon-publish-task.png
Binary files differ
diff --git a/apps/bMiniApp/src/assets/workbenches/icon-task-manage.png b/apps/bMiniApp/src/assets/workbenches/icon-task-manage.png
new file mode 100644
index 0000000..94b8284
--- /dev/null
+++ b/apps/bMiniApp/src/assets/workbenches/icon-task-manage.png
Binary files differ
diff --git a/apps/bMiniApp/src/components/Chunk/Cell.vue b/apps/bMiniApp/src/components/Chunk/Cell.vue
index 1a63c89..5aec162 100644
--- a/apps/bMiniApp/src/components/Chunk/Cell.vue
+++ b/apps/bMiniApp/src/components/Chunk/Cell.vue
@@ -1,5 +1,5 @@
 <template>
-  <div class="bole-cell-wrapper" v-bind="$attrs">
+  <div class="bole-cell-wrapper">
     <div class="cell-title-wrapper" v-if="showTitle">
       <slot name="title">
         <div :class="titleSize === 'normal' ? 'cell-title' : 'cell-title-large'">{{ title }}</div>
diff --git a/apps/bMiniApp/src/constants/router.ts b/apps/bMiniApp/src/constants/router.ts
index 8aa78f5..2be53e1 100644
--- a/apps/bMiniApp/src/constants/router.ts
+++ b/apps/bMiniApp/src/constants/router.ts
@@ -25,4 +25,6 @@
   setting = '/subpackages/mine/setting/setting',
   mineFavorites = '/subpackages/mine/mineFavorites/mineFavorites',
   mineContactRecord = '/subpackages/mine/mineContactRecord/mineContactRecord',
+
+  publishTask = '/subpackages/task/publishTask/publishTask',
 }
diff --git a/apps/bMiniApp/src/constants/task.ts b/apps/bMiniApp/src/constants/task.ts
new file mode 100644
index 0000000..24588f2
--- /dev/null
+++ b/apps/bMiniApp/src/constants/task.ts
@@ -0,0 +1,64 @@
+export enum TaskStatus {
+  All = 0,
+  WaitSign = 10,
+  Effect = 20,
+  Terminated = 30,
+}
+
+export const TaskStatusText = {
+  [TaskStatus.All]: '鍏ㄩ儴',
+  [TaskStatus.WaitSign]: '寰呯绾�',
+  [TaskStatus.Effect]: '鐢熸晥涓�',
+  [TaskStatus.Terminated]: '宸茬粓姝�',
+};
+
+export const TaskStatusColor = {
+  [TaskStatus.WaitSign]: '#FF7D00',
+  [TaskStatus.Effect]: '#3A71FF',
+  [TaskStatus.Terminated]: '#9FA4AC',
+};
+
+export enum SalaryTimeTypeEnum {
+  /**
+   * 鏈堣柂
+   */
+  Month = 10,
+  /**
+   * 鍛ㄨ柂
+   */
+  Week = 20,
+  /**
+   * 鏃ヨ柂
+   */
+  Day = 30,
+  /**
+   * 鏃惰柂
+   */
+  Hour = 40,
+}
+
+export const SalaryTimeTypeEnumText = {
+  [SalaryTimeTypeEnum.Month]: '鏈堣柂',
+  [SalaryTimeTypeEnum.Week]: '鍛ㄨ柂',
+  [SalaryTimeTypeEnum.Day]: '鏃ヨ柂',
+  [SalaryTimeTypeEnum.Hour]: '鏃惰柂',
+};
+
+export const SalaryTimeTypeEnumUnit = {
+  [SalaryTimeTypeEnum.Month]: '鍏�/鏈�',
+  [SalaryTimeTypeEnum.Week]: '鍏�/鍛�',
+  [SalaryTimeTypeEnum.Day]: '鍏�/澶�',
+  [SalaryTimeTypeEnum.Hour]: '鍏�/灏忔椂',
+};
+
+export enum SalaryType {
+  month = 10,
+  week = 20,
+  day = 30,
+}
+
+export const SalaryTypeText = {
+  [SalaryType.month]: '鏈堢粨',
+  [SalaryType.week]: '鍛ㄧ粨',
+  [SalaryType.day]: '鏃ョ粨',
+};
diff --git a/apps/bMiniApp/src/pages/mine/index.scss b/apps/bMiniApp/src/pages/mine/index.scss
index a42a18d..428f289 100644
--- a/apps/bMiniApp/src/pages/mine/index.scss
+++ b/apps/bMiniApp/src/pages/mine/index.scss
@@ -163,26 +163,6 @@
 
     .mine-content-service-list {
       display: flex;
-
-      .mine-content-service--list-item {
-        display: flex;
-        flex-direction: column;
-        align-items: center;
-        justify-content: center;
-        margin-right: 60px;
-
-        .mine-content-service--list-item-icon {
-          width: 72px;
-          height: 72px;
-          margin-bottom: 24px;
-        }
-
-        .mine-content-service--list-item-text {
-          font-size: 24px;
-          line-height: 36px;
-          color: boleGetCssVar('text-color', 'regular');
-        }
-      }
     }
   }
 
diff --git a/apps/bMiniApp/src/pages/mine/index.vue b/apps/bMiniApp/src/pages/mine/index.vue
index 25d5ffb..70e0c29 100644
--- a/apps/bMiniApp/src/pages/mine/index.vue
+++ b/apps/bMiniApp/src/pages/mine/index.vue
@@ -52,39 +52,36 @@
           </div>
         </div> -->
       </UserHomeTopView>
-      <div class="mine-content-record">
-        <div class="mine-content-record-item" @click="goMineFavorites">
-          <img class="mine-content-record-item-icon" :src="IconCollect" alt="" />
-          <nut-badge top="0" right="0" :value="8" color="#FF7D00">
-            <div class="mine-content-record-item-text">鎴戠殑鏀惰棌</div>
-          </nut-badge>
-        </div>
-        <div class="mine-content-record-item" @click="goMineContactRecord">
-          <img class="mine-content-record-item-icon" :src="IconRecord" alt="" />
-          <nut-badge top="0" right="0" :value="8" color="#FF7D00">
-            <div class="mine-content-record-item-text">鑱旂郴璁板綍</div>
-          </nut-badge>
-        </div>
-      </div>
-      <Cell :title="'鏇村鏈嶅姟'" class="mine-content-service">
-        <div class="mine-content-service-list">
-          <div class="mine-content-service--list-item">
-            <img class="mine-content-service--list-item-icon" :src="IconFinance" alt="" />
-            <div class="mine-content-service--list-item-text">璐㈠姟绠$悊</div>
+      <template v-if="isLogin">
+        <div class="mine-content-record">
+          <div class="mine-content-record-item" @click="goMineFavorites">
+            <img class="mine-content-record-item-icon" :src="IconCollect" alt="" />
+            <nut-badge top="0" right="0" :value="8" color="#FF7D00">
+              <div class="mine-content-record-item-text">鎴戠殑鏀惰棌</div>
+            </nut-badge>
           </div>
-          <div class="mine-content-service--list-item">
-            <img class="mine-content-service--list-item-icon" :src="IconRealName" alt="" />
-            <div class="mine-content-service--list-item-text">浼佷笟瀹炲悕</div>
-          </div>
-          <div class="mine-content-service--list-item" @click="goSetting">
-            <img class="mine-content-service--list-item-icon" :src="IconSetting" alt="" />
-            <div class="mine-content-service--list-item-text">璁剧疆</div>
+          <div class="mine-content-record-item" @click="goMineContactRecord">
+            <img class="mine-content-record-item-icon" :src="IconRecord" alt="" />
+            <nut-badge top="0" right="0" :value="8" color="#FF7D00">
+              <div class="mine-content-record-item-text">鑱旂郴璁板綍</div>
+            </nut-badge>
           </div>
         </div>
-      </Cell>
-      <nut-button type="info" class="mine-content-logout" @click="handleLoginout"
-        >閫�鍑虹櫥褰�</nut-button
-      >
+        <Cell :title="'鏇村鏈嶅姟'" class="mine-content-service">
+          <div class="mine-content-service-list">
+            <TaskDetailWelfareItem :icon="IconFinance" text="璐㈠姟绠$悊"></TaskDetailWelfareItem>
+            <TaskDetailWelfareItem :icon="IconRealName" text="浼佷笟瀹炲悕"></TaskDetailWelfareItem>
+            <TaskDetailWelfareItem
+              :icon="IconSetting"
+              text="璁剧疆"
+              @click="goSetting"
+            ></TaskDetailWelfareItem>
+          </div>
+        </Cell>
+        <nut-button type="info" class="mine-content-logout" @click="handleLoginout"
+          >閫�鍑虹櫥褰�</nut-button
+        >
+      </template>
     </ContentView>
   </PageLayoutWithBg>
 </template>
@@ -106,6 +103,7 @@
 import { Message } from '@12333/utils';
 import { useUserStore } from '@/stores/modules/user';
 import { useQueryClient } from '@tanstack/vue-query';
+import { TaskDetailWelfareItem } from '@12333/components';
 
 const userStore = useUserStore();
 const queryClient = useQueryClient();
diff --git a/apps/bMiniApp/src/pages/workbenches/InnerPage.vue b/apps/bMiniApp/src/pages/workbenches/InnerPage.vue
index 77f18e3..c62b8c3 100644
--- a/apps/bMiniApp/src/pages/workbenches/InnerPage.vue
+++ b/apps/bMiniApp/src/pages/workbenches/InnerPage.vue
@@ -1,13 +1,85 @@
 <template>
-  <div>InnerPage</div>
+  <ContentView>
+    <div class="workbenches-banner-wrapper">
+      <nut-swiper :auto-play="3000">
+        <nut-swiper-item v-for="(item, index) in list" :key="index">
+          <img :src="item" class="banner-img" draggable="false" />
+        </nut-swiper-item>
+      </nut-swiper>
+    </div>
+
+    <Cell :show-title="false" class="workbenches-cell">
+      <CellChunk title="浠诲姟">
+        <div class="workbenches-cell-list">
+          <TaskDetailWelfareItem :icon="IconPublishTask" text="鍙戝竷浠诲姟" @click="goPublishTask" />
+          <TaskDetailWelfareItem :icon="IconPersonManage" text="鐢ㄤ汉绠$悊" />
+        </div>
+      </CellChunk>
+      <CellChunk title="鐢ㄤ汉">
+        <div class="workbenches-cell-list">
+          <TaskDetailWelfareItem :icon="IconFlexjobManage" text="鐏靛伐绠$悊" />
+          <TaskDetailWelfareItem :icon="IconTaskManage" text="浠诲姟绠$悊" />
+          <TaskDetailWelfareItem :icon="IconAcceptManage" text="楠屾敹绠$悊" />
+        </div>
+      </CellChunk>
+    </Cell>
+  </ContentView>
 </template>
 
 <script setup lang="ts">
+import Taro from '@tarojs/taro';
+import { TaskDetailWelfareItem } from '@12333/components';
+import { RouterPath } from '@/constants';
+import IconAcceptManage from '@/assets/workbenches/icon-accept-manage.png';
+import IconFlexjobManage from '@/assets/workbenches/icon-flexjob-manage.png';
+import IconPersonManage from '@/assets/workbenches/icon-person-manage.png';
+import IconPublishTask from '@/assets/workbenches/icon-publish-task.png';
+import IconTaskManage from '@/assets/workbenches/icon-task-manage.png';
+
 defineOptions({
   name: 'InnerPage',
 });
+
+const list = ref([
+  'https://storage.360buyimg.com/jdc-article/NutUItaro34.jpg',
+  'https://storage.360buyimg.com/jdc-article/NutUItaro2.jpg',
+  'https://storage.360buyimg.com/jdc-article/welcomenutui.jpg',
+  'https://storage.360buyimg.com/jdc-article/fristfabu.jpg',
+]);
+
+function goPage(routeName: string) {
+  Taro.navigateTo({
+    url: routeName,
+  });
+}
+
+function goPublishTask() {
+  goPage(RouterPath.publishTask);
+}
 </script>
 
 <style lang="scss">
 @import '@/styles/common.scss';
+
+.workbenches-page-wrapper {
+  .workbenches-banner-wrapper {
+    .banner-img {
+      width: 100%;
+      height: 260px;
+      object-fit: cover;
+    }
+  }
+
+  .workbenches-cell {
+    margin-top: 24px;
+
+    .cell-title-wrapper {
+      margin-bottom: 36px;
+    }
+
+    .workbenches-cell-list {
+      display: flex;
+    }
+  }
+}
 </style>
diff --git a/apps/bMiniApp/src/subpackages/task/publishTask/InnerPage.vue b/apps/bMiniApp/src/subpackages/task/publishTask/InnerPage.vue
new file mode 100644
index 0000000..e30e4ca
--- /dev/null
+++ b/apps/bMiniApp/src/subpackages/task/publishTask/InnerPage.vue
@@ -0,0 +1,209 @@
+<template>
+  <ContentScrollView :paddingH="false">
+    <nut-form :model-value="form" ref="formRef" :rules="rules">
+      <nut-form-item label="浠诲姟鍚嶇О:" class="bole-form-item" prop="name" label-width="90px">
+        <nut-input v-model="form.name" placeholder="璇疯緭鍏ヤ换鍔″悕绉�"> </nut-input>
+      </nut-form-item>
+      <nut-form-item
+        label="鏈嶅姟璐�:"
+        class="bole-form-item"
+        prop="salaryTimeType"
+        required
+        label-width="90px"
+      >
+        <nut-radio-group v-model="form.salaryTimeType" direction="horizontal">
+          <BlRadio :label="Number(key)" v-for="(val, key) in SalaryTimeTypeEnumText" :key="key">{{
+            val
+          }}</BlRadio>
+        </nut-radio-group>
+      </nut-form-item>
+      <nut-form-item label=" " class="bole-form-item" prop="welfare" label-width="90px">
+        <div class="bole-form-input-wrapper">
+          <nut-input
+            v-model.trim="form.welfare"
+            class="nut-input-text bole-input-text"
+            placeholder="璇疯緭鍏ユ湇鍔¤垂"
+            type="text"
+          />
+          <div class="form-input-unit">{{ SalaryTimeTypeEnumUnit[form.salaryTimeType] }}</div>
+        </div>
+      </nut-form-item>
+      <nut-form-item
+        label="缁撶畻鏂瑰紡:"
+        class="bole-form-item"
+        prop="salaryType"
+        required
+        label-width="90px"
+      >
+        <nut-radio-group v-model="form.salaryType" direction="horizontal">
+          <BlRadio :label="Number(key)" v-for="(val, key) in SalaryTypeText">{{ val }}</BlRadio>
+        </nut-radio-group>
+      </nut-form-item>
+      <nut-form-item label="绂忓埄:" class="bole-form-item" prop="welfare" label-width="90px">
+        <ChooseInputWithPicker
+          v-model="form.welfare"
+          placeholder="璇烽�夋嫨绂忓埄"
+          :value-enum="TaskStatusText"
+        />
+      </nut-form-item>
+      <nut-form-item
+        label="骞撮緞鑼冨洿:"
+        class="bole-form-item"
+        prop="ageStart"
+        required
+        label-width="90px"
+      >
+        <div class="bole-form-input-wrapper">
+          <NumberInput
+            v-model.trim="form.ageStart"
+            class="nut-input-text bole-input-text"
+            placeholder="璇烽�夋嫨骞撮緞鑼冨洿"
+            :min="1"
+          />
+          <div class="form-input-separator">鑷�</div>
+          <NumberInput
+            v-model.trim="form.ageEnd"
+            class="nut-input-text bole-input-text"
+            placeholder="璇烽�夋嫨骞撮緞鑼冨洿"
+            :min="1"
+          />
+        </div>
+      </nut-form-item>
+      <nut-form-item label="鎬у埆:" class="bole-form-item" prop="welfare" label-width="90px">
+        <ChooseInputWithPicker
+          v-model="form.welfare"
+          placeholder="璇烽�夋嫨鎬у埆瑕佹眰"
+          :value-enum="TaskStatusText"
+        />
+      </nut-form-item>
+      <nut-form-item label="璧勬牸璇佷功:" class="bole-form-item" prop="welfare" label-width="90px">
+        <ChooseInputWithPicker
+          v-model="form.welfare"
+          placeholder="璇烽�夋嫨瑕佹眰鐨勮祫鏍艰瘉涔�"
+          :value-enum="TaskStatusText"
+        />
+      </nut-form-item>
+      <nut-form-item label="浠诲姟鍦扮偣" class="bole-form-item" prop="weMapInfo" required>
+        <ChooseLocationInput placeholder="璇烽�夋嫨浠诲姟鎵�鍦ㄥ湴" v-model="form.weMapInfo" />
+      </nut-form-item>
+      <nut-form-item label="璇︾粏鍦板潃:" class="bole-form-item" prop="name" label-width="90px">
+        <nut-input v-model="form.name" placeholder="璇疯緭鍏ヨ缁嗗湴鍧�"> </nut-input>
+      </nut-form-item>
+      <nut-form-item
+        label="浠诲姟寮�濮嬫棩鏈�:"
+        class="bole-form-item"
+        prop="startDate"
+        label-width="90px"
+      >
+        <ChooseInputWithDatePicker v-model="form.startDate"></ChooseInputWithDatePicker>
+      </nut-form-item>
+      <nut-form-item label="浠诲姟缁撴潫鏃ユ湡:" class="bole-form-item" prop="endDate" label-width="90px">
+        <ChooseInputWithDatePicker v-model="form.endDate"></ChooseInputWithDatePicker>
+      </nut-form-item>
+    </nut-form>
+  </ContentScrollView>
+  <PageFooter>
+    <PageFooterBtn type="primary" plain @click="handleCancel">鍙栨秷</PageFooterBtn>
+    <PageFooterBtn type="primary" @click="handleConfirm">鍙戝竷</PageFooterBtn>
+  </PageFooter>
+</template>
+
+<script setup lang="ts">
+import {
+  TaskStatus,
+  TaskStatusText,
+  SalaryTypeText,
+  SalaryType,
+  SalaryTimeTypeEnum,
+  SalaryTimeTypeEnumText,
+  SalaryTimeTypeEnumUnit,
+} from '@/constants/task';
+import { useUser } from '@/hooks';
+import {
+  ChooseInputWithPicker,
+  ChooseInputWithDatePicker,
+  NumberInput,
+  ChooseLocationInput,
+  Radio as BlRadio,
+} from '@12333/components';
+import { FormValidator } from '@12333/utils';
+import { FormRules } from '@nutui/nutui-taro/dist/types/__VUE/form/types';
+import Taro from '@tarojs/taro';
+
+defineOptions({
+  name: 'InnerPage',
+});
+
+const { userDetail } = useUser();
+
+const form = reactive({
+  name: '',
+  welfare: TaskStatus.All,
+  salaryTimeType: SalaryTimeTypeEnum.Month,
+  salaryType: SalaryType.month,
+  startDate: '',
+  endDate: '',
+  ageStart: '',
+  ageEnd: '',
+  weMapInfo: {} as WeMapModel,
+});
+
+const rules = reactive<FormRules>({
+  name: [{ required: true, message: '璇疯緭鍏ヤ换鍔″悕绉�' }],
+
+  weMapInfo: [
+    { required: true, message: '璇疯缃伐浣滃湴鐐�', validator: FormValidator.validatorWeMap },
+  ],
+
+  ageStart: [
+    {
+      required: true,
+      message: '璇疯緭鍏ュ勾榫勮姹�',
+      validator: () => {
+        if (!form.ageStart) {
+          return Promise.reject('璇疯緭鍏ュ勾榫勮姹�');
+        }
+        if (!form.ageEnd) {
+          return Promise.reject('璇疯緭鍏ュ勾榫勮姹�');
+        }
+        if (Number(form.ageEnd) <= Number(form.ageStart)) {
+          return Promise.reject('鏈�澶у勾榫勪笉鑳藉皬浜庢渶灏忓勾榫�');
+        }
+        return Promise.resolve(true);
+      },
+    },
+  ],
+});
+const formRef = ref<any>(null);
+function handleConfirm() {
+  if (!formRef.value) return;
+  formRef.value.validate().then(({ valid, errors }: any) => {
+    if (valid) {
+      confirm();
+    }
+  });
+}
+
+function confirm() {}
+
+function handleCancel() {
+  Taro.navigateBack();
+}
+</script>
+
+<style lang="scss">
+@import '@/styles/common.scss';
+
+.publishTask-page-wrapper {
+  .bole-form-input-wrapper {
+    display: flex;
+    align-items: center;
+  }
+
+  .form-input-unit {
+    margin-left: 10px;
+    color: boleGetCssVar('text-color', 'primary');
+    flex-shrink: 0;
+  }
+}
+</style>
diff --git a/apps/bMiniApp/src/subpackages/task/publishTask/publishTask.config.ts b/apps/bMiniApp/src/subpackages/task/publishTask/publishTask.config.ts
new file mode 100644
index 0000000..305fdb1
--- /dev/null
+++ b/apps/bMiniApp/src/subpackages/task/publishTask/publishTask.config.ts
@@ -0,0 +1,3 @@
+export default definePageConfig({
+  disableScroll: true,
+});
diff --git a/apps/bMiniApp/src/subpackages/task/publishTask/publishTask.vue b/apps/bMiniApp/src/subpackages/task/publishTask/publishTask.vue
new file mode 100644
index 0000000..bc207c6
--- /dev/null
+++ b/apps/bMiniApp/src/subpackages/task/publishTask/publishTask.vue
@@ -0,0 +1,17 @@
+<template>
+  <PageLayout class="publishTask-page-wrapper" :title="'鍙戝竷鎷涜仒'" has-border>
+    <InnerPage></InnerPage>
+  </PageLayout>
+</template>
+
+<script setup lang="ts">
+import InnerPage from './InnerPage.vue';
+
+defineOptions({
+  name: 'publishTask',
+});
+</script>
+
+<style lang="scss">
+@import '@/styles/common.scss';
+</style>
diff --git a/apps/cMiniApp/src/subpackages/task/taskDetail/InnerPage.vue b/apps/cMiniApp/src/subpackages/task/taskDetail/InnerPage.vue
index 7b64f7d..e8cb4e3 100644
--- a/apps/cMiniApp/src/subpackages/task/taskDetail/InnerPage.vue
+++ b/apps/cMiniApp/src/subpackages/task/taskDetail/InnerPage.vue
@@ -28,11 +28,11 @@
       <Cell :show-title="false">
         <CellChunk title="绂忓埄淇℃伅">
           <div class="taskDetail-welfare-list">
-            <TaskDetailWelfareItem />
-            <TaskDetailWelfareItem />
-            <TaskDetailWelfareItem />
-            <TaskDetailWelfareItem />
-            <TaskDetailWelfareItem />
+            <TaskDetailWelfareItem :icon="IconAttentioActive" text="楂樻俯琛ヨ创" />
+            <TaskDetailWelfareItem :icon="IconAttentioActive" text="楂樻俯琛ヨ创" />
+            <TaskDetailWelfareItem :icon="IconAttentioActive" text="楂樻俯琛ヨ创" />
+            <TaskDetailWelfareItem :icon="IconAttentioActive" text="楂樻俯琛ヨ创" />
+            <TaskDetailWelfareItem :icon="IconAttentioActive" text="楂樻俯琛ヨ创" />
           </div>
         </CellChunk>
         <CellChunk title="鎶ュ悕鏉′欢">
@@ -86,7 +86,7 @@
 import { useQuery } from '@tanstack/vue-query';
 import * as orderServices from '@12333/services/api/Order';
 import { useToggle } from 'senin-mini/hooks';
-import { TaskPrice } from '@12333/components';
+import { TaskPrice, TaskDetailWelfareItem } from '@12333/components';
 import IconAttention from '@/assets/task/icon-attention.png';
 import IconAttentioActive from '@/assets/task/icon-attention-active.png';
 import { RectRight } from '@nutui/icons-vue-taro';
@@ -95,7 +95,6 @@
 import IconSafe from '@/assets/task/icon-safe.png';
 import IconLocaltion from '@/assets/task/icon-localtion.png';
 import './taskDetail.scss';
-import TaskDetailWelfareItem from '../components/TaskDetailWelfareItem.vue';
 import CompanyDesc from '../components/CompanyDesc.vue';
 
 defineOptions({
diff --git a/packages/components/assets/components/icon-location.png b/packages/components/assets/components/icon-location.png
new file mode 100644
index 0000000..f807c40
--- /dev/null
+++ b/packages/components/assets/components/icon-location.png
Binary files differ
diff --git a/apps/cMiniApp/src/subpackages/task/components/TaskDetailWelfareItem.vue b/packages/components/src/Card/TaskDetailWelfareItem.vue
similarity index 68%
rename from apps/cMiniApp/src/subpackages/task/components/TaskDetailWelfareItem.vue
rename to packages/components/src/Card/TaskDetailWelfareItem.vue
index cdbf61c..307077d 100644
--- a/apps/cMiniApp/src/subpackages/task/components/TaskDetailWelfareItem.vue
+++ b/packages/components/src/Card/TaskDetailWelfareItem.vue
@@ -1,20 +1,21 @@
 <template>
   <div class="taskDetail-welfare-list-item">
-    <img :src="IconAttentioActive" class="taskDetail-welfare-list-item-icon" />
-    <div class="taskDetail-welfare-list-item-text">楂樻俯琛ヨ创</div>
+    <img :src="icon" class="taskDetail-welfare-list-item-icon" />
+    <div class="taskDetail-welfare-list-item-text">{{ text }}</div>
   </div>
 </template>
 
 <script setup lang="ts">
-import IconAttentioActive from '@/assets/task/icon-attention-active.png';
-
 defineOptions({
   name: 'TaskDetailWelfareItem',
 });
 
-// type Props = {};
+type Props = {
+  icon: string;
+  text: string;
+};
 
-// const props = withDefaults(defineProps<Props>(), {});
+const props = withDefaults(defineProps<Props>(), {});
 </script>
 
 <style lang="scss">
diff --git a/packages/components/src/Input/ChooseLocationInput.vue b/packages/components/src/Input/ChooseLocationInput.vue
new file mode 100644
index 0000000..d576d5e
--- /dev/null
+++ b/packages/components/src/Input/ChooseLocationInput.vue
@@ -0,0 +1,103 @@
+<template>
+  <nut-input
+    class="nut-input-text bole-input-text"
+    type="text"
+    input-align="right"
+    readonly
+    @click="handleChooseLocation"
+    :modelValue="props.modelValue.address"
+    alwaysEmbed
+  >
+    <template #clear>
+      <slot name="clear"></slot>
+    </template>
+    <template #left>
+      <slot name="left"></slot>
+    </template>
+    <template #right>
+      <slot name="right">
+        <img :src="IconLocation" class="choose-location-input-icon" />
+      </slot>
+    </template>
+  </nut-input>
+</template>
+
+<script setup lang="ts">
+import Taro from '@tarojs/taro';
+import IconLocation from '../../assets/components/icon-location.png';
+import { computed } from 'vue';
+import { useAllAreaList } from '@12333/hooks';
+
+defineOptions({
+  name: 'ChooseLocationInput',
+});
+
+type Props = {
+  modelValue: WeMapModel;
+};
+
+const props = defineProps<Props>();
+
+const emit = defineEmits<{
+  (e: 'update:modelValue', value: Props['modelValue']): void;
+}>();
+
+const { findAreaCodeFromName } = useAllAreaList();
+
+const innerModelValue = computed({
+  get() {
+    return props.modelValue;
+  },
+  set(val) {
+    emit('update:modelValue', val);
+  },
+});
+
+function handleChooseLocation() {
+  Taro.chooseLocation({
+    success: function (res) {
+      console.log('res: ', res);
+      const latitude = res.latitude as unknown as number;
+      const longitude = res.longitude as unknown as number;
+      let provinceName = '';
+      let cityName = '';
+      let countyName = '';
+      let nameList = res.address.match(
+        /.+?(鐪亅琛屾斂鍖簗甯倈鑷不鍖簗鑷不宸瀨琛屾斂鍗曚綅|鐩焲甯傝緰鍖簗鏃梶娴峰煙|宀泑鍘縷鍖�)/g
+      );
+      if (nameList) {
+        if (nameList?.length === 2) {
+          provinceName = nameList[0];
+          cityName = nameList[0];
+          countyName = nameList[1];
+        } else {
+          provinceName = nameList[0];
+          cityName = nameList[1];
+          countyName = nameList[2];
+        }
+      }
+      emit('update:modelValue', {
+        latitude,
+        longitude,
+        provinceName,
+        cityName,
+        countyName,
+        provinceCode: findAreaCodeFromName(provinceName),
+        cityCode: findAreaCodeFromName(cityName),
+        countyCode: findAreaCodeFromName(countyName),
+        address: res.address,
+      });
+    },
+  });
+}
+</script>
+
+<style lang="scss">
+@import '@/styles/common.scss';
+
+.choose-location-input-icon {
+  width: 19px;
+  height: 25px;
+  margin-left: 10px;
+}
+</style>
diff --git a/packages/components/src/index.ts b/packages/components/src/index.ts
index 5db4afc..9547599 100644
--- a/packages/components/src/index.ts
+++ b/packages/components/src/index.ts
@@ -13,6 +13,7 @@
 export { default as ChooseInputWithDatePicker } from './Input/ChooseInputWithDatePicker.vue';
 export { default as ChooseInputWithAreaPicker } from './Input/ChooseInputWithAreaPicker.vue';
 export { default as ChooseInputWithAreaSheet } from './Input/ChooseInputWithAreaSheet.vue';
+export { default as ChooseLocationInput } from './Input/ChooseLocationInput.vue';
 export { default as PreviewImage } from './Image/PreviewImage.vue';
 export { default as ImageGrid } from './Image/ImageGrid.vue';
 export { default as AutoWidthImage } from './Image/AutoWidthImage.vue';
@@ -23,6 +24,7 @@
 export { default as MyTaskCard } from './Card/MyTaskCard.vue';
 export { default as FlexJobCard } from './Card/FlexJobCard.vue';
 export { default as TaskPrice } from './Card/TaskPrice.vue';
+export { default as TaskDetailWelfareItem } from './Card/TaskDetailWelfareItem.vue';
 export { default as QueryMenuView } from './Menu/QueryMenuView.vue';
 export { default as QueryMenuItem } from './Menu/QueryMenuItem.vue';
 export { default as ProRadio } from './Form/ProRadio.vue';
diff --git a/packages/components/types/global.d.ts b/packages/components/types/global.d.ts
index c1e51fb..0563d9d 100644
--- a/packages/components/types/global.d.ts
+++ b/packages/components/types/global.d.ts
@@ -16,4 +16,16 @@
   import { ComponentOptions } from 'vue'
   const componentOptions: ComponentOptions
   export default componentOptions
+}
+
+declare interface WeMapModel {
+  latitude?: number;
+  longitude?: number;
+  provinceName?: string;
+  cityName?: string;
+  countyName?: string;
+  provinceCode?: number;
+  cityCode?: number;
+  countyCode?: number;
+  address?: string;
 }
\ No newline at end of file

--
Gitblit v1.9.1