Selaa lähdekoodia

Merge branch 'master' of http://git.dgtis.com/zhangningning/ali_ai_learn_web

zhangningning 1 kuukausi sitten
vanhempi
commit
9fc39cd183
51 muutettua tiedostoa jossa 2297 lisäystä ja 5 poistoa
  1. 26 2
      src/App.vue
  2. 42 0
      src/api/my.js
  3. BIN
      src/assets/imgs/header-bj@2x.png
  4. BIN
      src/assets/imgs/line@2x.png
  5. BIN
      src/assets/imgs/my/bianji@2x.png
  6. BIN
      src/assets/imgs/my/del@2x.png
  7. BIN
      src/assets/imgs/my/dui@2x.png
  8. BIN
      src/assets/imgs/my/edit@2x.png
  9. BIN
      src/assets/imgs/my/guanbi@2x.png
  10. BIN
      src/assets/imgs/my/huiyuan@2x.png
  11. BIN
      src/assets/imgs/my/icon1@2x.png
  12. BIN
      src/assets/imgs/my/icon1a@2x.png
  13. BIN
      src/assets/imgs/my/icon2@2x.png
  14. BIN
      src/assets/imgs/my/icon2a@2x.png
  15. BIN
      src/assets/imgs/my/icon3@2x.png
  16. BIN
      src/assets/imgs/my/icon3a@2x.png
  17. BIN
      src/assets/imgs/my/icon4@2x.png
  18. BIN
      src/assets/imgs/my/icon4a@2x.png
  19. BIN
      src/assets/imgs/my/icon5@2x.png
  20. BIN
      src/assets/imgs/my/icon5a@2x.png
  21. BIN
      src/assets/imgs/my/icon6@2x.png
  22. BIN
      src/assets/imgs/my/icon6a@2x.png
  23. BIN
      src/assets/imgs/my/icon7@2x.png
  24. BIN
      src/assets/imgs/my/icon7a@2x.png
  25. BIN
      src/assets/imgs/my/jilu@2x.png
  26. BIN
      src/assets/imgs/my/order1@2x.png
  27. BIN
      src/assets/imgs/my/order2@2x.png
  28. BIN
      src/assets/imgs/my/order3@2x.png
  29. BIN
      src/assets/imgs/my/order4@2x.png
  30. BIN
      src/assets/imgs/my/order5@2x.png
  31. BIN
      src/assets/imgs/my/qiandao@2x.png
  32. BIN
      src/assets/imgs/my/quxiao@2x.png
  33. BIN
      src/assets/imgs/my/shanchu@2x.png
  34. BIN
      src/assets/imgs/my/star-a@2x.png
  35. BIN
      src/assets/imgs/my/star@2x.png
  36. BIN
      src/assets/imgs/my/tixian@2x.png
  37. BIN
      src/assets/imgs/my/vip@2x.png
  38. BIN
      src/assets/imgs/my/zhuanhuan@2x.png
  39. 56 0
      src/locales/en.js
  40. 58 0
      src/locales/zh-CN.js
  41. 169 0
      src/pages/Member.vue
  42. 145 0
      src/pages/Personal/Collection.vue
  43. 439 0
      src/pages/Personal/Demand.vue
  44. 140 0
      src/pages/Personal/Invoice.vue
  45. 96 0
      src/pages/Personal/MemberDetails.vue
  46. 243 0
      src/pages/Personal/Orders.vue
  47. 188 0
      src/pages/Personal/Wallet.vue
  48. 275 0
      src/pages/Personal/Workflow.vue
  49. 361 0
      src/pages/PersonalCenter.vue
  50. 49 2
      src/router/index.js
  51. 10 1
      src/styles/index.scss

+ 26 - 2
src/App.vue

@@ -1,5 +1,5 @@
 <template>
-  <div id="app" :class="{'isHomePage': $route.path === '/' || $route.path === '/index'}">
+  <div id="app" :class="{'isHomePage': $route.path === '/' || $route.path === '/index',vipHomePage: $route.path === '/member'}">
     <ElConfigProvider :locale="langStore.elLocale">
     <el-container style="min-height: 100vh;">
       <el-header class="box_shadow_card">
@@ -26,6 +26,7 @@
               <template #dropdown>
                 <el-dropdown-menu>
                   <el-dropdown-item @click="handleLogout">{{ $t('common.logout') }}</el-dropdown-item>
+                   <el-dropdown-item @click="toPersonal">{{ $t('personalCenter.personalCenter') }}</el-dropdown-item>
                 </el-dropdown-menu>
               </template>
             </el-dropdown>
@@ -37,6 +38,7 @@
       </el-header>
       <!-- 固定头部占位 -->
       <div style="height: 60px;"></div>
+      <div class="header-bj" v-if="$route.path === '/member'"></div>
       <el-main class="container">
         <router-view />
       </el-main>
@@ -110,8 +112,16 @@ const activeIndex = computed(() => {
   if (route.path.startsWith('/mibi-shop')) {
     return '5'
   }
-  return '' // 默认返回首页
+  if (route.path.startsWith('/personal-center')) {
+    return null
+  }
+  return null // 默认返回首页
 });
+// 去个人中心
+const toPersonal = () => {
+  router.push('/personal-center/wallet')
+};
+
 // 处理注销
 const handleLogout = () => {
   logout().then(() => {
@@ -142,6 +152,11 @@ provide('openLoginDialog', openLoginDialog);
     background-size: 100% 100%;
   }
 }
+.vipHomePage {
+  .el-header {
+    background: rgba(255,255,255,0.5);
+  }
+}
 
 .el-header {
   background: url('@/assets/imgs/bg-header_2.png') no-repeat;
@@ -192,6 +207,15 @@ provide('openLoginDialog', openLoginDialog);
     }
   }
 }
+.header-bj {
+  top: 0;
+  width: 100%;
+  height: 463px;
+  background: url('/src/assets/imgs/header-bj@2x.png') no-repeat;
+  background-size: cover;
+  position: fixed;
+  z-index: -1;
+}
 
 .el-footer {
   color: #666;

+ 42 - 0
src/api/my.js

@@ -0,0 +1,42 @@
+import request from './request.js'
+// 签到
+export function checkIn(data = {}) {
+  return request.post('/in',data)
+}
+// 收藏列表
+export function collectList(data = {}) {
+  return request.get('/collect/list',data)
+}
+// 查询会员类型
+export function vipList(data = {}) {
+  return request.get('/type/list',data)
+}
+
+// 查询我的报名记录列表
+export function getWorkflowApplyByUserId(data = {}) {
+  return request.get('/apply/getWorkflowApplyByUserId',data)
+}
+// 查询登录用户的寻找工作流列表
+export function userQuestList(data = {}) {
+  return request.get('/quest/userQuestList',data)
+}
+
+// 我的订单
+export function orderList(data = {}) {
+  return request.get('/order/list',data)
+}
+
+// 我的发票
+export function invoiceList(data = {}) {
+  return request.get('/invoice/list',data)
+}
+
+// 查看登录用户发布的工作流
+export function userPublishList(data = {}) {
+  return request.get('/publish/userPublishList',data)
+}
+
+// 删除登录用户发布的工作流
+export function delectPublish(data = {}) {
+  return request.del(`/publish/${data}`)
+}

BIN
src/assets/imgs/header-bj@2x.png


BIN
src/assets/imgs/line@2x.png


BIN
src/assets/imgs/my/bianji@2x.png


BIN
src/assets/imgs/my/del@2x.png


BIN
src/assets/imgs/my/dui@2x.png


BIN
src/assets/imgs/my/edit@2x.png


BIN
src/assets/imgs/my/guanbi@2x.png


BIN
src/assets/imgs/my/huiyuan@2x.png


BIN
src/assets/imgs/my/icon1@2x.png


BIN
src/assets/imgs/my/icon1a@2x.png


BIN
src/assets/imgs/my/icon2@2x.png


BIN
src/assets/imgs/my/icon2a@2x.png


BIN
src/assets/imgs/my/icon3@2x.png


BIN
src/assets/imgs/my/icon3a@2x.png


BIN
src/assets/imgs/my/icon4@2x.png


BIN
src/assets/imgs/my/icon4a@2x.png


BIN
src/assets/imgs/my/icon5@2x.png


BIN
src/assets/imgs/my/icon5a@2x.png


BIN
src/assets/imgs/my/icon6@2x.png


BIN
src/assets/imgs/my/icon6a@2x.png


BIN
src/assets/imgs/my/icon7@2x.png


BIN
src/assets/imgs/my/icon7a@2x.png


BIN
src/assets/imgs/my/jilu@2x.png


BIN
src/assets/imgs/my/order1@2x.png


BIN
src/assets/imgs/my/order2@2x.png


BIN
src/assets/imgs/my/order3@2x.png


BIN
src/assets/imgs/my/order4@2x.png


BIN
src/assets/imgs/my/order5@2x.png


BIN
src/assets/imgs/my/qiandao@2x.png


BIN
src/assets/imgs/my/quxiao@2x.png


BIN
src/assets/imgs/my/shanchu@2x.png


BIN
src/assets/imgs/my/star-a@2x.png


BIN
src/assets/imgs/my/star@2x.png


BIN
src/assets/imgs/my/tixian@2x.png


BIN
src/assets/imgs/my/vip@2x.png


BIN
src/assets/imgs/my/zhuanhuan@2x.png


+ 56 - 0
src/locales/en.js

@@ -17,6 +17,7 @@ export default {
     hour: 'Hour',
     lijixuexi: 'Learn Now',
     renkanguo: 'People Have Seen',
+    renbaoming: 'People Registered',
     qitakechengtuijian: 'Other Course Recommendations',
     kechengjieshao: 'Course Description',
     kechengmulu: 'Course Directory',
@@ -51,6 +52,24 @@ export default {
     notes: ' Notes',
     copyError: 'Copy Failed',
     copySuccess: 'Copy Success',
+    signUpDeadline: 'Sign Up Deadline',
+    publish: 'Publish',
+    actualAmount: 'Actual Amount',
+    goPay: 'Go Pay',
+    cancelOrder: 'Cancel Order',
+    applyInvoice: 'Apply Invoice',
+    applyRefund: 'Apply Refund',
+    reorder: 'Reorder',
+    orderTime: 'Order Time',
+    collected: 'Collected',
+    cancelCollect: 'Cancel Collect',
+    orderCreateTime: 'Order Create Time',
+    viewDetails: 'View Details',
+    publishWorkflow: 'Publish Workflow',
+    agree: 'Agree',
+    reject: 'Reject',
+    viewHomepage: 'View Homepage',
+    empty:'No data available'
   },
   login: {
     smsLogin: 'SMS Login',
@@ -85,5 +104,42 @@ export default {
     signUpSuccess: 'Sign Up Success',
     signUpFailed: 'Sign Up Failed, please try again later',
     publishSuccess: 'Publish Success',
+  },
+  personalCenter:{
+    personalCenter: 'Personal Center',
+    phoneNumber: 'Phone Number',
+    follow: 'Follow',
+    editProfile: 'Edit Profile',
+    openMembership: 'Open Membership',
+    checkIn: 'Check In',
+    myWallet: 'My Wallet',
+    membershipInfo: 'Membership Info',
+    myCollection: 'My Collection',
+    myDemand: 'My Demand',
+    myOrders: 'My Orders',
+    myInvoice: 'My Invoice',
+    myWorkflow: 'My Workflow',
+    incomeDetails: 'Income Details',
+    usageRecord: 'Usage Record',
+    openMembershipDetails: 'Open Membership Details',
+    publishDemandRecord: 'Publish Demand Record',
+    myDemandRecord: 'My Demand Record',
+    viewSignUpRecord: 'View Sign Up Record',
+    endActivity: 'End Activity',
+    cancelSignUp: 'Cancel Sign Up',
+    allOrders: 'All Orders',
+    daifukuan: 'Pending Payment',
+    yiwancheng: 'Completed',
+    yiquxiao: 'Cancelled',
+    dingdanhao: 'Order Number',
+    goumaishichang: 'Purchase Duration',
+    youxiaoqi: 'Validity Period',
+    zhifushijian: 'Payment Time',
+    gongzuoliuliang: 'Workflow Quantity',
+    baomiliang: 'Registration Record',
+    ren: 'People',
+    yue: 'Balance',
+    shenqingtixian: 'Apply for Withdrawal',
+    zhuanghuanmibi: 'Convert Mibit'
   }
 }

+ 58 - 0
src/locales/zh-CN.js

@@ -1,3 +1,5 @@
+import PersonalCenter from "../pages/PersonalCenter.vue";
+
 export default {
   // 通用模块
   common: {
@@ -18,6 +20,7 @@ export default {
     hour: '小时',
     lijixuexi: '立即学习',
     renkanguo: '人看过',
+    renbaoming: '人报名',
     qitakechengtuijian: '其他课程推荐',
     kechengjieshao: '课程介绍',
     kechengmulu: '课程目录',
@@ -52,6 +55,24 @@ export default {
     notes: '篇笔记',
     copyError: '复制失败',
     copySuccess: '复制成功',
+    signUpDeadline: '报名截止时间',
+    publish: '发布',
+    actualAmount: '实际金额',
+    goPay: '去支付',
+    cancelOrder: '取消订单',
+    applyInvoice: '申请开票',
+    applyRefund: '申请退款',
+    reorder: '重新下单',
+    orderTime: '下单时间',
+    collected: '已收藏',
+    cancelCollect: '取消收藏',
+    orderCreateTime: '订单创建时间',
+    viewDetails: '查看详情',
+    publishWorkflow: '发布工作流',
+    agree: '同意',
+    reject: '拒绝',
+    viewHomepage: '查看主页',
+    empty:'暂无数据'
   },
   login: {
     smsLogin: '短信登录',
@@ -85,6 +106,43 @@ export default {
     signUpSuccess: '报名成功',
     signUpFailed: '报名失败,请稍后重试',
     publishSuccess: '发布成功',
+  },
+  personalCenter:{
+    personalCenter: '个人中心',
+    phoneNumber: '手机号',
+    follow: '关注',
+    editProfile: '编辑资料',
+    openMembership: '开通会员',
+    checkIn: '签到',
+    myWallet: '我的钱包',
+    membershipInfo: '会员信息',
+    myCollection: '我的收藏',
+    myDemand: '我的需求',
+    myOrders: '我的订单',
+    myInvoice: '我的发票',
+    myWorkflow: '我的工作流',
+    incomeDetails: '收益明细',
+    usageRecord: '使用记录',
+    openMembershipDetails: '开通会员明细',
+    publishDemandRecord: '发布需求记录',
+    myDemandRecord: '我的报名记录',
+    viewSignUpRecord: '查看报名记录',
+    endActivity: '结束活动',
+    cancelSignUp: '取消报名',
+    allOrders: '全部订单',
+    daifukuan: '待付款',
+    yiwancheng: '已完成',
+    yiquxiao: '已取消',
+    dingdanhao: '订单号',
+    goumaishichang: '购买时长',
+    youxiaoqi: '有效期',
+    zhifushijian: '支付时间',
+    gongzuoliuliang: '工作流数量',
+    baomiliang: '报名记录',
+    ren: '人',
+    yue: '余额',
+    shenqingtixian: '申请提现',
+    zhuanghuanmibi: '转换米币'
   }
 
 }

+ 169 - 0
src/pages/Member.vue

@@ -0,0 +1,169 @@
+<template>
+  <div class="member">
+    <div class="member-head">
+      <div class="member-head-title">开通会员尊享特权</div>
+      <ul class="member-head-list">
+        <li v-for="(item, index) in 4" :key="index">小标题优惠文案</li>
+      </ul>
+    </div>
+    <ul class="member-list">
+      <li v-for="(item, index) in list" :key="index">
+        <div class="name">{{ item.typeName }}</div>
+        <div class="desc">xxxxxxxxxxxxxxxxxxxxxxxx</div>
+        <div class="flex-align-center price">
+          <div class="price-left">
+            <span>¥</span>
+            <span>{{ item.price }}</span>
+            <span>/月</span>
+          </div>
+          <div class="price-right">¥79.00/月</div>
+        </div>
+        <div class="btn">开通月卡</div>
+        <div class="line">尊享权益</div>
+        <div class="ul">
+          <div v-for="(item, index) in 4" :key="index" class="li flex-center-between">
+            <div class="">权益一</div>
+            <div class="">限量</div>
+          </div>
+        </div>
+      </li>
+    </ul>
+  </div>
+</template>
+<script setup lang="ts">
+import { vipList } from '@/api/my.js';
+import { ref, onMounted } from 'vue';
+const list = ref([])
+
+const getList = async () => {
+  let res = await vipList();
+  console.log(res.data)
+  list.value = res.data;
+}
+
+onMounted(() => {
+  getList()
+})
+
+</script>
+<style>
+body {
+  /* background: #FBF4F0 !important; */
+}
+</style>
+<style lang="scss">
+.member {
+  max-width: 1246px;
+  margin: 0 auto;
+}
+
+.member-head {
+  padding: 70px 0;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  flex-direction: column;
+  line-height: 1;
+
+  .member-head-title {
+    color: #8B3D22;
+    font-size: 36px;
+    font-weight: bold;
+  }
+
+  .member-head-list {
+    display: flex;
+
+    margin-top: 24px;
+
+    li {
+      font-size: 18px;
+      margin-right: 66px;
+
+      &:last-child {
+        margin-right: 0;
+      }
+    }
+  }
+}
+
+.member-list {
+  display: flex;
+  gap: 48px;
+  flex-wrap: wrap;
+
+  li {
+    width: 383px;
+    padding: 24px 32px;
+    background: #FFFFFF;
+    border-radius: 16px;
+    display: flex;
+    align-items: center;
+    flex-direction: column;
+
+    .desc {
+      margin: 16px 0 24px;
+      font-size: 16px;
+    }
+
+    .name {
+      color: #8B3D22;
+      font-size: 24px;
+      font-weight: bold;
+    }
+
+    .price {
+      font-size: 14px;
+      line-height: 1;
+      align-items: flex-end;
+
+      .price-left {
+        span {
+          &:nth-child(2) {
+            font-size: 24px;
+            font-weight: bold;
+          }
+        }
+      }
+
+      .price-right {
+        margin-left: 20px;
+      }
+    }
+
+    .btn {
+      width: 100%;
+      margin: 24px 0;
+      color: #5A1D07;
+      font-size: 16px;
+      font-weight: bold;
+      text-align: center;
+      line-height: 50px;
+      cursor: pointer;
+      background: linear-gradient(270deg, #FBE8CF 0%, #F8C79D 52.05%, #FADCB9 100%);
+      border-radius: 10px;
+    }
+
+    .line {
+      width: 164px;
+      color: #8B3D22;
+      font-weight: bold;
+      font-size: 14px;
+      text-align: center;
+      background: url('/src/assets/imgs/line@2x.png') no-repeat;
+      background-size: 164px 3px;
+      background-position: center center;
+    }
+
+    .ul {
+      width: 100%;
+      color: #8B3D22;
+      font-size: 14px;
+
+      .li {
+        margin-top: 16px;
+      }
+    }
+  }
+}
+</style>

+ 145 - 0
src/pages/Personal/Collection.vue

@@ -0,0 +1,145 @@
+<template>
+  <div class="collection">
+    <div class="gap10 title">
+      <div class="line_vertical"></div>
+      <div class="">{{ $t('personalCenter.myCollection') }}</div>
+    </div>
+    <ul class="collection-list">
+      <li class="flex-center-between" v-for="(item, index) in list" :key="index">
+        <img class="image"
+          src="https://shadow.elemecdn.com/app/element/hamburger.9cf7b091-55e9-11e9-a976-7f4d0b07eef6.png" alt="">
+        <div class="collection-list-main">
+          <div class="collection-list-main-left">
+            <div class="titles">UI界面设计教程</div>
+            <div class="gap10 tag">
+              <el-button type="primary" size="large" plain>技能标签</el-button>
+            </div>
+            <div class="">这是课程介绍这是课程介绍这是课程介绍这是课程介绍这是课程介绍这是课程介绍这是课程介绍这是课程介绍这是课程介绍</div>
+          </div>
+          <div class="btn flex-center">
+            <img src="/src/assets/imgs/my/star-a@2x.png" alt="">
+            <div class="">{{ index == 0 ? $t('common.collected') : $t('common.cancelCollect') }}</div>
+          </div>
+        </div>
+      </li>
+    </ul>
+    <template v-if="list.length">
+      <Pagination :total="form.total" :page-size="form.pageSize" :current-page="form.pageNum"
+        @page-change="handlePageChange" />
+    </template>
+    <el-empty v-else :description="$t('common.empty')" />
+  </div>
+</template>
+<script setup lang="ts">
+import Pagination from '@/components/Pagination.vue'
+import { ref, onMounted } from 'vue'
+import { collectList } from '@/api/my.js'
+const form = ref({
+  pageNum: 1,
+  pageSize: 10,
+  total: 0
+})
+
+const list = ref([])
+
+const getList = async () => {
+  let res = await collectList(form.value);
+  console.log(res);
+  form.value.total = res.total;
+  list.value = res.rows
+}
+const handlePageChange = (page) => {
+  list.value = []
+  form.value.pageNum = page;
+  getList()
+}
+onMounted(() => {
+  getList()
+})
+</script>
+<style scoped lang="scss">
+.collection {
+  padding-bottom: 20px;
+
+  .title {
+    height: 60px;
+    font-size: 20px;
+    font-weight: bold;
+    color: #333333;
+  }
+
+  .collection-list {
+    li {
+      padding: 16px;
+      margin-bottom: 16px;
+      background: #F5F7FA;
+      border-radius: 16px;
+
+      &:last-child {
+        margin-bottom: 0;
+      }
+
+      .image {
+        width: 213px;
+        height: 120px;
+        object-fit: cover;
+        border-radius: 8px;
+        margin-right: 16px;
+      }
+
+      .collection-list-main {
+        flex: 1;
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+
+        .collection-list-main-left {
+          flex: 1;
+          margin-right: 16px;
+
+          .titles {
+            font-size: 18px;
+            font-weight: bold;
+            color: #333333;
+          }
+
+          .tag {
+            margin: 8px 0;
+          }
+
+          .content {
+            color: #666666;
+            font-size: 14px;
+            line-height: 22px;
+          }
+        }
+
+        .btn {
+          width: 120px;
+          height: 32px;
+          color: #FFFFFF;
+          font-size: 14px;
+          cursor: pointer;
+          background: linear-gradient(270deg, #0055FE 0%, #C832FA 100%);
+          border-radius: 4px;
+
+          &:hover {
+            opacity: 0.7;
+          }
+
+          img {
+            width: 14px;
+            height: 14px;
+            margin-right: 4px;
+          }
+        }
+
+        .active {
+          background: #FFFFFF;
+          color: #2D71FF;
+        }
+      }
+    }
+  }
+}
+</style>

+ 439 - 0
src/pages/Personal/Demand.vue

@@ -0,0 +1,439 @@
+<template>
+  <div class="demand">
+    <el-tabs v-model="form.activeName" class="demo-tabs" @tab-click="handleClick">
+      <el-tab-pane v-for="tab in tabs" :key="tab.name" :label="$t(tab.label)" :name="tab.name">
+        <ul class="demand-list">
+          <li v-for="(item, index) in list" :key="index">
+            <div class="flex-center-between">
+              <div class="title">{{ item.title }}</div>
+              <div class="price">¥{{ item.budgetMin }}-{{ item.budgetMax }}</div>
+            </div>
+            <div class="flex-align-center content">
+              <div class="flex-align-center">
+                <el-button type="primary" size="small" plain>一级分类名称</el-button>
+                <el-button type="primary" size="small" plain>二级分类名称</el-button>
+              </div>
+              <ul class="flex-align-center list">
+                <div class="li">
+                  <img src="/src/assets/imgs/yuangong.png" alt="">
+                  <div class="">{{ item.publishCount }}{{ $t('common.renbaoming') }}</div>
+                </div>
+                <div class="li">
+                  <img src="/src/assets/imgs/rili.png" alt="">
+                  <div class="">{{ $t('common.signUpDeadline') }}:{{ item.publishTime }}</div>
+                </div>
+              </ul>
+            </div>
+            <div class="description">这是需求描述这是需求描述这是需求描述这是需求描述这是需求描述这是需求描述这是需求描述</div>
+            <div class="info">
+              <div class="info-left">
+                <el-avatar :size="30" :src="appStore.avatarDefault" />
+                <div class="name">{{ item.nickName }}</div>
+                <div class="date">2024-11-18 {{ $t('common.publish') }}</div>
+              </div>
+              <div class="info-right flex-align-center">
+                <template v-if="form.activeName === 0">
+                  <div class="btn" @click="dialogVisible = true">
+                    <img src="/src/assets/imgs/my/jilu@2x.png" alt="">
+                    <div>{{ $t('personalCenter.viewSignUpRecord') }}</div>
+                  </div>
+                  <div class="btn">
+                    <img src="/src/assets/imgs/my/bianji@2x.png" alt="">
+                    <div>{{ $t('common.edit') }}</div>
+                  </div>
+                  <div class="btn">
+                    <img src="/src/assets/imgs/my/guanbi@2x.png" alt="">
+                    <div class="red">{{ $t('personalCenter.endActivity') }}</div>
+                  </div>
+                  <div class="btn">
+                    <img src="/src/assets/imgs/my/shanchu@2x.png" alt="">
+                    <div class="red">{{ $t('common.delete') }}</div>
+                  </div>
+                </template>
+
+                <div class="btn" v-else>
+                  <img src="/src/assets/imgs/my/quxiao@2x.png" alt="">
+                  <div class="red">{{ $t('personalCenter.cancelSignUp') }}</div>
+                </div>
+
+              </div>
+            </div>
+          </li>
+        </ul>
+      </el-tab-pane>
+    </el-tabs>
+   <template v-if="list.length">
+     <Pagination :total="form.total" :page-size="form.pageSize" :current-page="form.pageNum" @page-change="handlePageChange" />
+   </template>
+   <el-empty v-else :description="$t('common.empty')" />
+
+    <el-dialog v-model="dialogVisible" :title="$t('personalCenter.viewSignUpRecord')" width="1138">
+      <div class="detail">
+        <div class="detail-top">
+          <div class="flex-center-between">
+            <div class="flex-align-center">
+              <div class="tag">报名中</div>
+              <div class="name">{{ item.title }}</div>
+            </div>
+            <div class="price">¥{{ item.budgetMin }}-{{ item.budgetMax }}</div>
+          </div>
+          <div class="flex-align-center content">
+            <div class="flex-align-center">
+              <el-button type="primary" size="small" plain>一级分类名称</el-button>
+              <el-button type="primary" size="small" plain>二级分类名称</el-button>
+            </div>
+            <ul class="flex-align-center list">
+              <div class="li">
+                <img src="/src/assets/imgs/yuangong.png" alt="">
+                <div class="">15{{ $t('common.renbaoming') }}</div>
+              </div>
+              <div class="li">
+                <img src="/src/assets/imgs/rili.png" alt="">
+                <div class="">{{ $t('common.signUpDeadline') }}:2024-11-19 17:00</div>
+              </div>
+            </ul>
+          </div>
+          <div class="desc">
+            此n8n工作流是一款强大的AI驱动的潜在客户富集与通知系统,专为市场营销和销售团队设计。它通过智能表单收集线索,利用OpenAI深度分析并丰富客户数据,自动识别关键信息。系统能根据预设条件,通过多种渠道即时发送个性化通知,显著提升线索质量、转化率及团队协作效率,是优化客户关系管理的关键工具。
+          </div>
+          <div class="time">2024-11-18 {{ $t('common.publish') }}</div>
+        </div>
+        <div class="detail-txt">{{ $t('personalCenter.baomiliang') }}(5 {{ $t('personalCenter.ren') }})</div>
+        <ul class="detail-list">
+          <li v-for="(item, index) in 5" :key="index">
+            <div class="flex-align-center detail-list-left">
+              <el-avatar :size="20" :src="''" />
+              <div class="">花花</div>
+              <div class="">13176012742</div>
+            </div>
+            <div class="detail-list-number">{{ $t('personalCenter.gongzuoliuliang') }}:15</div>
+            <div class="flex-align-center detail-list-right">
+              <div class="lex-align-center btn green">
+                <img src="/src/assets/imgs/my/dui@2x.png" alt="">
+                <div class="">{{ $t('common.agree') }}</div>
+              </div>
+              <div class="lex-align-center btn red">
+                <img src="/src/assets/imgs/my/quxiao@2x.png" alt="">
+                <div class="">{{ $t('common.reject') }}</div>
+              </div>
+              <div class="lex-align-center btn blue">
+                <img src="/src/assets/imgs/my/jilu@2x.png" alt="">
+                <div class="">{{ $t('common.viewHomepage') }}</div>
+              </div>
+            </div>
+          </li>
+        </ul>
+      </div>
+      <template #footer>
+        <div class="dialog-footer flex-center">
+          <el-button @click="dialogVisible = false">{{ $t('common.cancel') }}</el-button>
+          <el-button type="primary" class="gradient" @click="dialogVisible = false">
+            {{ $t('common.confirm') }}
+          </el-button>
+        </div>
+      </template>
+    </el-dialog>
+
+  </div>
+</template>
+<script lang="ts" setup>
+import { ref,onMounted } from 'vue'
+import { useAppStore } from '@/pinia/appStore'
+import type { TabsPaneContext } from 'element-plus'
+import Pagination from '@/components/Pagination.vue'
+
+import { getWorkflowApplyByUserId,userQuestList } from '@/api/my.js'
+
+const appStore = useAppStore();
+const tabs = ref([
+  { label: 'personalCenter.publishDemandRecord', name: 0 },
+  { label: 'personalCenter.myDemandRecord', name: 1 }
+])
+
+const dialogVisible = ref(false)
+
+const list = ref([])
+const form = ref({
+  pageNum:1,
+  pageSize:10,
+  total: 0,
+  activeName:0
+})
+
+const handleClick = (tab: TabsPaneContext) => {
+  list.value = []
+  form.value.pageNum = 1;
+  form.value.activeName = tab.props.name;
+  getList()
+}
+
+// 获取列表
+const getList = async () =>{
+  let res = await (form.value.activeName === 0 ? userQuestList(form.value) : getWorkflowApplyByUserId(form.value))
+  console.log(res.rows)
+  list.value = res.rows || [];
+  form.value.total = res.total;
+}
+
+const handlePageChange = (page) =>{
+  list.value = []
+  form.value.pageNum = page;
+  getList()
+}
+
+onMounted(()=>{
+  getList()
+})
+
+
+</script>
+<style scoped lang="scss">
+.demand {
+  padding-bottom: 20px;
+
+  div {
+    line-height: 1;
+  }
+
+  .demand-list {
+    li {
+      padding: 16px;
+      margin-bottom: 16px;
+      background: #F5F7FA;
+      border-radius: 16px;
+
+      &:last-child {
+        margin-bottom: 0;
+      }
+
+      .title {
+        font-size: 18px;
+        font-weight: bold;
+        color: #333333;
+      }
+
+
+
+      .description {
+        font-size: 16px;
+        color: #666666;
+        line-height: 24px;
+        margin: 8px 0;
+      }
+
+      .info {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+
+        .info-left {
+          display: flex;
+          align-items: center;
+
+          .name {
+            font-size: 16px;
+            margin: 0 8px;
+          }
+
+          .date {
+            font-size: 14px;
+            color: #666666;
+          }
+        }
+
+        .info-right {
+          .btn {
+            height: 32px;
+            display: flex;
+            align-items: center;
+            padding: 0px 16px;
+            background: #FFFFFF;
+            border-radius: 4px;
+            cursor: pointer;
+            margin-left: 8px;
+
+            img {
+              width: 14px;
+              height: 14px;
+              margin-right: 4px;
+            }
+
+            div {
+              font-size: 14px;
+              color: #2D71FF;
+            }
+
+            .red {
+              color: #E43434;
+            }
+          }
+        }
+
+      }
+
+      .price {
+        font-size: 24px;
+        color: #FD5F3C;
+      }
+    }
+  }
+}
+
+.content {
+  margin-top: 8px;
+
+  .list {
+    .li {
+      display: flex;
+      align-items: center;
+
+      img {
+        width: 16px;
+        height: 16px;
+        margin-right: 4px;
+      }
+
+      margin-left: 8px;
+
+      div {
+        font-size: 12px;
+      }
+    }
+  }
+}
+
+.detail {
+  padding: 16px;
+  border-top: 1px solid #EBEEF5;
+
+  .detail-top {
+    padding: 16px;
+    background: #F5F7FA;
+    border-radius: 16px;
+    border: 1px solid #FFFFFF;
+
+    .tag {
+      padding: 0 12px;
+      line-height: 30px;
+      font-size: 14px;
+      color: #FFFFFF;
+      background: #2D71FF;
+      border-radius: 4px;
+    }
+
+    .name {
+      font-size: 18px;
+      font-weight: bold;
+      color: #333333;
+      margin-left: 8px;
+    }
+
+    .price {
+      color: #FD5F3C;
+      font-size: 24px;
+    }
+
+    .desc {
+      margin: 8px 0;
+      line-height: 24px;
+      font-size: 16px;
+      color: #666666;
+    }
+
+    .time {
+      font-size: 14px;
+      color: #666666;
+    }
+  }
+
+  .detail-txt {
+    line-height: 58px;
+    font-size: 18px;
+    font-weight: bold;
+  }
+
+  .detail-list {
+    li {
+      display: flex;
+      padding: 0 16px;
+      align-items: center;
+      justify-content: space-between;
+      margin-bottom: 16px;
+      height: 64px;
+      background: #F5F7FA;
+      border-radius: 8px;
+
+      &:last-child {
+        margin-bottom: 0;
+      }
+
+      .detail-list-left {
+        div {
+          color: #666666;
+          font-size: 14px;
+
+          &:nth-child(2) {
+            margin: 0 8px;
+            font-size: 16px;
+            color: #333333;
+          }
+        }
+      }
+
+      .detail-list-number {
+        font-size: 14px;
+        color: #333333;
+      }
+
+      .detail-list-right {
+        .btn {
+          display: flex;
+          margin-left: 8px;
+          align-items: center;
+          cursor: pointer;
+          padding: 0px 16px;
+          height: 32px;
+          border-radius: 4px;
+          font-size: 14px;
+
+          &:hover {
+            opacity: 0.7;
+          }
+
+          img {
+            width: 14px;
+            height: 14px;
+            margin-right: 4px;
+          }
+        }
+
+        .green {
+          background: #E9F7EF;
+
+          div {
+            color: #1FB362;
+          }
+        }
+
+        .red {
+
+          background: #FCEBEB;
+
+          div {
+            color: #E43434;
+          }
+        }
+
+        .blue {
+
+          background: #EAF0FF;
+
+          div {
+            color: #2D71FF;
+          }
+        }
+      }
+    }
+  }
+}
+</style>

+ 140 - 0
src/pages/Personal/Invoice.vue

@@ -0,0 +1,140 @@
+<template>
+  <div class="invoice">
+    <div class="gap10 invoice-title">
+      <div class="line_vertical"></div>
+      <div class="">{{ $t('personalCenter.myInvoice') }}</div>
+    </div>
+    <ul class="invoice-list">
+      <li v-for="(item, index) in list" :key="index">
+        <div class="invoice-list-t flex-center-between">
+          <div class="">这是订单名称</div>
+          <div class="">¥5000.00</div>
+        </div>
+        <div class="flex-center-between invoice-list-c">
+          <div class="">{{ $t('personalCenter.orderNumber') }}:</div>
+          <div class="">20251024001</div>
+        </div>
+        <div class="flex-center-between invoice-list-time">
+          <div class="">{{ $t('common.orderCreateTime') }}:</div>
+          <div class="">2025-10-24 13:00</div>
+        </div>
+        <div class="flex-center-between invoice-list-b">
+          <div class=""></div>
+          <div class="">
+            <img src="/src/assets/imgs/my/jilu@2x.png" alt="">
+            <span>{{ $t('common.viewDetails') }}</span>
+          </div>
+        </div>
+      </li>
+    </ul>
+    <template v-if="list.length">
+      <Pagination :total="form.total" :page-size="form.pageSize" :current-page="form.pageNum"
+        @page-change="handlePageChange" />
+    </template>
+    <el-empty v-else :description="$t('common.empty')" />
+  </div>
+</template>
+<script setup lang="ts">
+import Pagination from '@/components/Pagination.vue'
+import { invoiceList } from '@/api/my.js'
+import { ref, onMounted } from 'vue'
+const list = ref([])
+const form = ref({
+  pageNum: 1,
+  pageSize: 10,
+  total: 0
+})
+
+
+// 获取列表
+const getList = async () => {
+  let res = await invoiceList(form.value)
+  console.log(res.rows)
+  list.value = res.rows || [];
+  form.value.total = res.total;
+}
+
+const handlePageChange = (page) => {
+  list.value = []
+  form.value.pageNum = page;
+  getList()
+}
+
+onMounted(() => {
+  getList()
+})
+</script>
+<style scoped lang="scss">
+.invoice {
+  padding-bottom: 20px;
+
+  .invoice-title {
+    height: 60px;
+    font-size: 20px;
+    font-weight: bold;
+    color: #333333;
+  }
+
+  .invoice-list {
+    li {
+      padding: 16px;
+      margin-bottom: 16px;
+      background: #F5F7FA;
+      border-radius: 16px;
+
+      &:last-child {
+        margin-bottom: 0;
+      }
+
+      .invoice-list-t {
+
+        div {
+          font-size: 18px;
+          font-weight: bold;
+          color: #3D3D3D;
+
+          &:last-child {
+            color: #FD5F3C;
+          }
+        }
+      }
+
+      .invoice-list-c,
+      .invoice-list-time,
+      .invoice-list-b {
+        margin-top: 8px;
+
+        div {
+          font-size: 16px;
+
+          &:first-child {
+            color: #666666;
+          }
+        }
+      }
+
+      .invoice-list-b {
+
+        div:last-child {
+          display: flex;
+          align-items: center;
+          cursor: pointer;
+          justify-content: center;
+          width: 106px;
+          height: 32px;
+          background: #FFFFFF;
+          border-radius: 4px;
+          color: #2D71FF;
+          font-size: 14px;
+
+          img {
+            width: 14px;
+            height: 14px;
+            margin-right: 4px;
+          }
+        }
+      }
+    }
+  }
+}
+</style>

+ 96 - 0
src/pages/Personal/MemberDetails.vue

@@ -0,0 +1,96 @@
+<template>
+  <div class="member-details">
+    <div class="gap10 title">
+      <div class="line_vertical"></div>
+      <div class="">{{ $t('personalCenter.openMembershipDetails') }}</div>
+    </div>
+    <ul class="member-details-list">
+      <li v-for="(item, index) in list" :key="index">
+        <div class="member-details-list-t flex-center-between">
+          <div class="">{{ $t('personalCenter.goumaishichang') }}:1个月</div>
+          <div class="">¥99.99</div>
+        </div>
+        <div class="member-details-list-b flex-center-between">
+          <div class="">{{ $t('personalCenter.youxiaoqi') }}:2026-01-01至2026-02-01</div>
+          <div class="">{{ $t('personalCenter.zhifushijian') }}:2026-01-01 16:11:11</div>
+        </div>
+      </li>
+    </ul>
+    <template v-if="list.length">
+      <Pagination :total="form.total" :page-size="form.pageSize" :current-page="form.pageNum"
+        @page-change="handlePageChange" />
+    </template>
+    <el-empty v-else :description="$t('common.empty')" />
+  </div>
+</template>
+<script setup lang="ts">
+import Pagination from '@/components/Pagination.vue'
+import { ref, onMounted } from 'vue'
+import { collectList } from '@/api/my.js'
+const form = ref({
+  pageNum: 1,
+  pageSize: 10,
+  total: 0
+})
+
+const list = ref([])
+
+const getList = async () => {
+  let res = await collectList(form.value);
+  console.log(res);
+  form.value.total = res.total;
+  list.value = res.rows
+}
+const handlePageChange = (page) => {
+  list.value = []
+  form.value.pageNum = page;
+  getList()
+}
+onMounted(() => {
+  getList()
+})
+</script>
+<style scoped lang="scss">
+.member-details {
+  padding-bottom: 20px;
+
+  .title {
+    height: 60px;
+    font-size: 20px;
+    font-weight: bold;
+    color: #333333;
+  }
+
+  .member-details-list {
+    li {
+      padding: 16px;
+      margin-bottom: 16px;
+      background: #F5F7FA;
+      border-radius: 16px;
+
+      &:last-child {
+        margin-bottom: 0;
+      }
+
+      .member-details-list-t {
+        margin-bottom: 8px;
+
+        div {
+          font-size: 16px;
+
+          &:last-child {
+            color: #F52929;
+          }
+        }
+      }
+
+      .member-details-list-b {
+        div {
+          font-size: 14px;
+          color: #666666;
+        }
+      }
+    }
+  }
+}
+</style>

+ 243 - 0
src/pages/Personal/Orders.vue

@@ -0,0 +1,243 @@
+<template>
+  <div class="order">
+    <el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
+      <el-tab-pane v-for="tab in tabs" :key="tab.name" :label="$t(tab.label)" :name="tab.name">
+        <ul class="order-list">
+          <li v-for="(item, index) in list" :key="index">
+            <div class="order-list-top flex-center-between">
+              <div class="order-list-top-l flex-align-center">
+                <el-tag :type="index == 0 ? 'primary' : index == 1 ? 'success' : 'danger'">{{ index == 0 ?
+                  $t('personalCenter.daifukuan') : index == 1 ? $t('personalCenter.yiwancheng') :
+                    $t('personalCenter.yiquxiao') }}</el-tag>
+                <div class="">{{ $t('personalCenter.dingdanhao') }}: 3056207306143088789</div>
+              </div>
+              <div class="order-list-top-r">{{ $t('common.orderTime') }}: 2025-11-11 12:00:00</div>
+            </div>
+            <div class="order-list-main flex">
+              <img class="image"
+                src="https://shadow.elemecdn.com/app/element/hamburger.9cf7b091-55e9-11e9-a976-7f4d0b07eef6.png" alt="">
+              <div class="order-list-con flex-center-between flex_1">
+                <div class="">
+                  <div class="title">UI界面设计教程</div>
+                  <div class="">
+                    <el-button type="primary" size="small" plain>技能标签</el-button>
+                    <el-button type="primary" size="small" plain>技能标签</el-button>
+                  </div>
+                </div>
+                <div class="mi_price">
+                  <div class="">29900</div>
+                  <div class="">{{ $t('common.mibi') }}</div>
+                </div>
+                <div class="mi_price price">
+                  <div class="">¥239.20</div>
+                  <div class="">{{ $t('common.actualAmount') }}</div>
+                </div>
+                <div class="">
+                  <template v-if="index == 0">
+                    <div class="gradient btn">
+                      <img src="/src/assets/imgs/my/order1@2x.png" alt="">
+                      <div class="">{{ $t('common.goPay') }}</div>
+                    </div>
+                    <div class="blue btn mt8">
+                      <img src="/src/assets/imgs/my/order2@2x.png" alt="">
+                      <div class="">{{ $t('common.cancelOrder') }}</div>
+                    </div>
+                  </template>
+                  <template v-else-if="index == 1">
+                    <div class="blue btn">
+                      <img src="/src/assets/imgs/my/order3@2x.png" alt="">
+                      <div class="">{{ $t('common.applyInvoice') }}</div>
+                    </div>
+                    <div class="red btn mt8">
+                      <img src="/src/assets/imgs/my/order4@2x.png" alt="">
+                      <div class="">{{ $t('common.applyRefund') }}</div>
+                    </div>
+                  </template>
+                  <template v-else-if="index == 2">
+                    <div class="btn gradient">
+                      <img src="/src/assets/imgs/my/order5@2x.png" alt="">
+                      <div class="">{{ $t('common.reorder') }}</div>
+                    </div>
+                  </template>
+                </div>
+              </div>
+            </div>
+          </li>
+        </ul>
+      </el-tab-pane>
+    </el-tabs>
+    <template v-if="list.length">
+      <Pagination :total="form.total" :page-size="form.pageSize" :current-page="form.pageNum"
+        @page-change="handlePageChange" />
+    </template>
+    <el-empty v-else :description="$t('common.empty')" />
+  </div>
+</template>
+<script lang="ts" setup>
+import { ref, onMounted } from 'vue'
+
+import type { TabsPaneContext } from 'element-plus'
+import Pagination from '@/components/Pagination.vue'
+import { orderList } from '@/api/my.js'
+
+const tabs = ref([
+  { label: 'personalCenter.allOrders', name: 'first' },
+  { label: 'personalCenter.daifukuan', name: 'second' },
+  { label: 'personalCenter.yiwancheng', name: 'third' },
+  { label: 'personalCenter.yiquxiao', name: 'fourth' },
+])
+
+const activeName = ref('first')
+const list = ref([]);
+const form = ref({
+  pageNum: 1,
+  pageSize: 10,
+  total: 0,
+  activeName: 0
+})
+
+const handleClick = (tab: TabsPaneContext) => {
+  list.value = []
+  form.value.pageNum = 1;
+  form.value.activeName = tab.props.name;
+  getList()
+}
+// 获取我的订单
+const getList = async () => {
+  let res = await orderList(form.value);
+  console.log(res.rows)
+  list.value = res.rows || [];
+  form.value.total = res.total;
+}
+const handlePageChange = (page) => {
+  list.value = []
+  form.value.pageNum = page;
+  getList()
+}
+
+onMounted(() => {
+  getList()
+})
+
+</script>
+<style scoped lang="scss">
+.order {
+  padding-bottom: 16px;
+
+  .order-list {
+    li {
+      background: #FFFFFF;
+      border-radius: 16rpx;
+      margin-bottom: 16px;
+
+      &:last-child {
+        margin-bottom: 0;
+      }
+
+      .order-list-top {
+        height: 42px;
+        padding: 0 16px;
+        background: #F5F7FA;
+        border-radius: 16px 16px 0px 0px;
+
+        .order-list-top-l {
+          div {
+            margin-left: 8px;
+            font-size: 16px;
+            font-weight: bold;
+          }
+        }
+
+        .order-list-top-r {
+          font-size: 14px;
+        }
+      }
+
+      .order-list-main {
+        padding: 16px;
+        border-radius: 0 0 16px 16px;
+        border: 1px solid #EBEEF5;
+
+        .image {
+          width: 160px;
+          height: 90px;
+          object-fit: cover;
+          margin-right: 16px;
+          border-radius: 8px;
+        }
+
+        .title {
+          font-size: 16px;
+          font-weight: bold;
+          margin-bottom: 8px;
+          line-height: 1;
+        }
+
+        .mi_price {
+
+          div {
+            font-size: 18px;
+            text-align: center;
+
+            &:last-child {
+              font-size: 12px;
+              color: #666666;
+            }
+          }
+        }
+
+        .price {
+          div {
+            &:first-child {
+              color: #FD5F3C;
+            }
+          }
+        }
+
+        .mt8 {
+          margin-top: 8px;
+        }
+
+        .btn {
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          width: 106px;
+          height: 32px;
+          cursor: pointer;
+          border-radius: 4px;
+
+          img {
+            width: 14px;
+            height: 14px;
+            margin-right: 4px;
+          }
+
+          div {
+            font-size: 14px;
+            color: #FFFFFF;
+          }
+        }
+
+
+
+        .red {
+          background: #FCEBEB;
+
+          div {
+            color: #E43434;
+          }
+        }
+
+        .blue {
+          background: #EAF0FF;
+
+          div {
+            color: #2D71FF;
+          }
+        }
+      }
+    }
+  }
+}
+</style>

+ 188 - 0
src/pages/Personal/Wallet.vue

@@ -0,0 +1,188 @@
+<template>
+  <div class="wallet-page">
+    <ul class="wallet-list flex-between">
+      <li class="gradient flex-center-between" v-for="(item, index) in 2" :key="index">
+        <div class="wallet-list-li-left">
+          <div class="">{{ index == 0 ? $t('common.mibi') : $t('common.baomibi') }}{{ $t('personalCenter.yue') }}</div>
+          <div class="">5000</div>
+        </div>
+        <div class="wallet-list-li-right flex-align-center">
+          <div class="flex-align-center btn">
+            <img src="/src/assets/imgs/my/tixian@2x.png" alt="">
+            <div class="">{{ $t('personalCenter.shenqingtixian') }}</div>
+          </div>
+          <div v-if="index == 1" class="flex-align-center btn">
+            <img src="/src/assets/imgs/my/zhuanhuan@2x.png" alt="">
+            <div class="">{{ $t('personalCenter.zhuanghuanmibi') }}</div>
+          </div>
+        </div>
+      </li>
+    </ul>
+    <el-tabs v-model="form.activeName" class="demo-tabs" @tab-click="handleClick">
+      <el-tab-pane :label="$t(tab.label)" v-for="tab in tabs" :key="tab.name" :name="tab.name">
+        <div class="tabs flex-align-center">
+          <div :class="{active:index == 0}" class="tab" v-for="(item, index) in 2">{{ index == 0 ? '米币' : '暴米币' }}明细</div>
+        </div>
+        <ul class="wallet-page-list">
+          <li v-for="(item, index) in list" :key="index">
+            <div class="title">
+              <div class="">订单米币</div>
+              <div class="">2024-08-24 14:11:11</div>
+            </div>
+            <div class="price">+1000</div>
+          </li>
+        </ul>
+      </el-tab-pane>
+    </el-tabs>
+    <template v-if="list.length">
+      <Pagination :total="form.total" :page-size="form.pageSize" :current-page="form.pageNum"
+        @page-change="handlePageChange" />
+    </template>
+    <el-empty v-else :description="$t('common.empty')" />
+  </div>
+</template>
+<script lang="ts" setup>
+import { ref, onMounted } from 'vue'
+
+import type { TabsPaneContext } from 'element-plus'
+import Pagination from '@/components/Pagination.vue'
+
+const activeName = ref('first')
+const tabs = ref([
+  { label: 'personalCenter.incomeDetails', name: 0 },
+  { label: 'personalCenter.usageRecord', name: 1 }
+])
+const list = ref([])
+const form = ref({
+  activeName: 0,
+  pageNum: 1,
+  pageSize: 10,
+  total: 0,
+})
+
+const handleClick = (tab: TabsPaneContext) => {
+  list.value = []
+  form.value.pageNum = 1;
+  form.value.activeName = tab.props.name;
+  getList()
+}
+const getList = async () => {
+
+}
+
+const handlePageChange = (newPage: number) => {
+  list.value = []
+  form.value.pageNum = page;
+  getList()
+}
+onMounted(() => {
+  getList()
+})
+</script>
+<style scoped lang="scss">
+.wallet-page {
+
+  padding-bottom: 16px;
+
+  .tabs {
+    .tab {
+      cursor: pointer;
+      color: #2D71FF;
+      padding: 0 12px;
+      line-height: 30px;
+      font-size: 14px;
+      background: #EAF0FF;
+      border-radius: 4px;
+      margin-right: 16px;
+    }
+    .active {
+      color: #FFFFFF;
+      background: linear-gradient( 90deg, #0055FE 0%, #C832FA 100%);
+    }
+  }
+
+  .wallet-list {
+    gap: 16px;
+    padding: 16px;
+
+    li {
+      flex: 1;
+      padding: 16px;
+      border-radius: 16px;
+
+      .wallet-list-li-left {
+
+        div {
+          color: #FFFFFF;
+          font-size: 14px;
+          line-height: 1;
+
+          &:last-child {
+            margin-top: 8px;
+            font-size: 32px;
+            font-weight: bold;
+          }
+        }
+      }
+
+      .wallet-list-li-right {
+        .btn {
+          cursor: pointer;
+          margin-left: 8px;
+          color: #2D71FF;
+          font-size: 14px;
+          padding: 0 20px;
+          height: 40px;
+          background: #FFFFFF;
+          border-radius: 10px;
+
+          img {
+            width: 16px;
+            height: 16px;
+            margin-right: 4px;
+          }
+
+          &:hover {
+            opacity: 0.7;
+          }
+        }
+      }
+    }
+  }
+}
+
+.wallet-page-list {
+  li {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    padding: 16px;
+    border-radius: 16px;
+    background: #F5F7FA;
+    margin-bottom: 16px;
+
+    &:last-child {
+      margin-bottom: 0;
+    }
+
+    .title {
+      div {
+        font-size: 16px;
+        line-height: 1;
+
+        &:last-child {
+          margin-top: 8px;
+          color: #666666;
+          font-size: 14px;
+        }
+      }
+    }
+
+    .price {
+      font-size: 16px;
+      font-weight: bold;
+      color: #F52929;
+    }
+  }
+}
+</style>

+ 275 - 0
src/pages/Personal/Workflow.vue

@@ -0,0 +1,275 @@
+<template>
+  <div class="workflow">
+    <div @click="router.push({path:'/workflow-add'})" class="gradient workflow-btn flex-center">
+      <img src="/src/assets/imgs/add.png" alt="">
+      <div class="">{{ $t('common.publishWorkflow') }}</div>
+    </div>
+    <ul class="workflow-list">
+      <li v-for="(item, index) in list" :key="index" class="">
+        <img class="image" :src="item.coverImage" alt="">
+        <div class="kong"></div>
+        <div class="workflow-list-con flex-column flex-between">
+          <div class="top">
+            <div class="workflow-list-time flex-align-center">
+              <img src="/src/assets/imgs/rili.png" alt="">
+              <div class="">{{ item.createTime }}</div>
+            </div>
+            <div class="title">{{ item.workflowTitle }}</div>
+            <div class="desc">{{ item.description }}</div>
+          </div>
+          <div class="flex_1">
+            <div class="info flex-center-between">
+              <div class="info-left flex-align-center">
+                <el-avatar :size="30" :src="''" />
+                <div class="">花花</div>
+              </div>
+              <div class="info-right flex-align-center">
+                <img src="/src/assets/imgs/yun.png" alt="">
+                <div class="">{{ item.categoryName1 }}平台</div>
+              </div>
+            </div>
+            <div class="footer flex-center-between">
+              <div @click="changeItem(item, index, 0)" class="flex-center btn">
+                <img src="/src/assets/imgs/my/edit@2x.png" alt="">
+                <div class="">{{ $t('common.edit') }}</div>
+              </div>
+              <div @click="changeItem(item, index, 1)" class="flex-center btn">
+                <img src="/src/assets/imgs/my/del@2x.png" alt="">
+                <div class="">{{ $t('common.delete') }}</div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </li>
+    </ul>
+    <template v-if="list.length">
+      <Pagination :total="form.total" :page-size="form.pageSize" :current-page="form.pageNum"
+        @page-change="handlePageChange" />
+    </template>
+    <el-empty v-else :description="$t('common.empty')" />
+  </div>
+</template>
+<script setup lang="ts">
+
+import Pagination from '@/components/Pagination.vue'
+
+import { ref, onMounted } from 'vue';
+
+import { useRoute, useRouter } from 'vue-router'
+
+import { userPublishList, delectPublish } from '@/api/my'
+
+import { ElMessageBox } from 'element-plus'
+
+import DGTMessage from '@/utils/message'
+
+const route = useRoute()
+const router = useRouter()
+
+let list = ref([])
+const form = ref({
+  categoryId1: null,
+  categoryId2: null,
+  categoryId3: null,
+  workflowTitle: ''
+})
+// 编辑删除
+const changeItem = async (item: any, index: any, type: any) => {
+  if (type == 0) {
+
+  } else if (type == 1) {
+    ElMessageBox.confirm(
+      'proxy will permanently delete the file. Continue?',
+      'Warning',
+      {
+        confirmButtonText: 'OK',
+        cancelButtonText: 'Cancel',
+        type: 'warning',
+      }
+    )
+      .then(async () => {
+        console.log('222', item)
+        let res = await delectPublish(item.publishId);
+        DGTMessage.success('删除成功')
+        getList()
+        console.log(res);
+      })
+      .catch(() => {
+
+      })
+  }
+}
+
+const getList = async () => {
+  let res = await userPublishList(form.value);
+  console.log(res);
+  form.value.total = res.total;
+  list.value = res.rows
+}
+const handlePageChange = (page) => {
+  list.value = []
+  form.value.pageNum = page;
+  getList()
+}
+onMounted(() => {
+  getList()
+})
+
+</script>
+<style scoped lang="scss">
+.workflow {
+  padding: 16px 0 20px;
+
+  .workflow-btn {
+    height: 50px;
+    color: #FFFFFF;
+    cursor: pointer;
+    border-radius: 10px;
+    font-size: 18px;
+
+    &:hover {
+      opacity: 0.9;
+    }
+
+    img {
+      width: 30px;
+      height: 30px;
+      margin-right: 4px;
+    }
+  }
+
+  .workflow-list {
+    gap: 16px;
+    display: flex;
+    flex-wrap: wrap;
+    margin-top: 16px;
+
+    li {
+      width: 380px;
+      cursor: pointer;
+      position: relative;
+      background: #F5F7FA;
+      border-radius: 16px;
+      overflow: hidden;
+      border: 1px solid #FFFFFF;
+
+      .image {
+        width: 100%;
+        height: 204px;
+        display: block;
+        object-fit: cover;
+        border-radius: 16px 16px 0 0;
+      }
+
+      .kong {
+        height: 166px;
+      }
+
+      .workflow-list-con {
+        height: 224px;
+        padding: 16px;
+        left: 0;
+        right: 0;
+        bottom: 0;
+        position: absolute;
+        transform: translateY(58px);
+        transition: transform 0.3s ease;
+
+        background: #F5F7FA;
+        border-radius: 0px 0px 16px 16px;
+
+        .top {
+          line-height: 1;
+          height: 120px;
+          display: flex;
+          flex-direction: column;
+        }
+
+        .workflow-list-time {
+          font-size: 14px;
+
+          img {
+            width: 16px;
+            height: 16px;
+            margin-right: 8px;
+          }
+        }
+
+        .title {
+          margin: 8px 0;
+          font-size: 18px;
+          font-weight: bold;
+          display: -webkit-box;
+          -webkit-box-orient: vertical;
+          -webkit-line-clamp: 2;
+          overflow: hidden;
+          text-overflow: ellipsis;
+          line-height: 26px;
+        }
+
+        .desc {
+          white-space: nowrap;
+          overflow: hidden;
+          text-overflow: ellipsis;
+        }
+
+        .info {
+          font-size: 14px;
+
+          .info-left {
+            div {
+              margin-left: 8px;
+            }
+          }
+
+          .info-right {
+            padding: 0 4px;
+            height: 22px;
+            background: #E9F3FF;
+            border-radius: 4px;
+
+            img {
+              width: 16px;
+              height: 16px;
+              margin-right: 8px;
+            }
+          }
+        }
+
+        .footer {
+          margin-top: 8px;
+
+          .btn {
+            width: 166px;
+            height: 40px;
+            font-size: 14px;
+            color: #2D71FF;
+            background: #FFFFFF;
+            border-radius: 10px;
+
+            img {
+              width: 16px;
+              height: 16px;
+              margin-right: 4px;
+            }
+
+            &:last-child {
+              color: #E43434;
+            }
+
+            &:hover {
+              opacity: 0.7;
+            }
+          }
+        }
+      }
+
+      &:hover {
+        .workflow-list-con {
+          transform: translateY(0);
+        }
+      }
+    }
+  }
+}
+</style>

+ 361 - 0
src/pages/PersonalCenter.vue

@@ -0,0 +1,361 @@
+<template>
+  <div class="personal">
+    <Breadcrumb />
+    <div class="personal-head">
+      <div class="personal-head-left">
+        <el-avatar :size="100" :src="appStore.avatarDefault" />
+        <div class="personal-user-info">
+          <div class="personal-username">
+            <div class="">{{ userInfo.nickName }}</div>
+            <img src="/src/assets/imgs/my/vip@2x.png" alt="">
+          </div>
+          <div class="personal-user-phone mt4">{{ $t('personalCenter.phoneNumber') }}:{{ userInfo.userPhone }}</div>
+          <div class="gap10 mt4">
+            <el-button type="primary" size="large" plain>技能标签</el-button>
+          </div>
+          <div class="personal-user-list">
+            <div class="personal-user-li">
+              <span>0</span>
+              <span>{{ $t('common.mibi') }}</span>
+            </div>
+            <div class="personal-user-line"></div>
+            <div class="personal-user-li">
+              <span>0</span>
+              <span>{{ $t('common.baomibi') }}</span>
+            </div>
+            <div class="personal-user-line"></div>
+            <div class="personal-user-li">
+              <span>0</span>
+              <span>{{ $t('personalCenter.follow') }}</span>
+            </div>
+          </div>
+        </div>
+
+      </div>
+      <div class="personal-head-right">
+        <div class="personal-head-right-li">
+          <img src="/src/assets/imgs/my/bianji@2x.png" alt="">
+          <div class="">{{ $t('personalCenter.editProfile') }}</div>
+        </div>
+        <div @click="router.push({path:'/member'})" class="personal-head-right-li">
+          <img src="/src/assets/imgs/my/huiyuan@2x.png" alt="">
+          <div class="">{{ $t('personalCenter.openMembership') }}</div>
+        </div>
+        <div @click="signIn" class="personal-head-right-li gradient">
+          <img src="/src/assets/imgs/my/qiandao@2x.png" alt="">
+          <div class="">{{ $t('personalCenter.checkIn') }}</div>
+        </div>
+      </div>
+    </div>
+    <div class="personal-main">
+      <div class="personal-left">
+        <div class="personal-left-list">
+          <div @click="toPath(item, index)" :class="{ active: index == navIndex }" class="personal-left-li"
+            v-for="(item, index) in navList" :key="index">
+            <img v-if="index == navIndex" :src="item.iconActive" alt="">
+            <img v-else :src="item.icon" alt="">
+            <div class="">{{ $t(item.name) }}</div>
+          </div>
+        </div>
+      </div>
+      <div class="personal-right">
+        <div class="personal-right-main">
+          <router-view />
+        </div>
+
+      </div>
+    </div>
+  </div>
+</template>
+<script setup lang="ts">
+import { useAppStore } from '@/pinia/appStore'
+
+import { ref, onMounted,computed } from 'vue';
+import { useRoute, useRouter } from 'vue-router'
+
+import { getUserInfo } from '@/api/auth.js'
+import { checkIn } from '@/api/my.js'
+
+const appStore = useAppStore();
+const route = useRoute()
+const router = useRouter()
+const navList = ref([
+  {
+    name: 'personalCenter.myWallet',
+    path: '/personal-center/wallet',
+    icon: '/src/assets/imgs/my/icon1@2x.png',
+    iconActive: '/src/assets/imgs/my/icon1a@2x.png'
+  },
+  {
+    name: 'personalCenter.membershipInfo',
+    path: '/personal-center/member-details',
+    icon: '/src/assets/imgs/my/icon2@2x.png',
+    iconActive: '/src/assets/imgs/my/icon2a@2x.png'
+  },
+  {
+    name: 'personalCenter.myCollection',
+    path: '/personal-center/collection',
+    icon: '/src/assets/imgs/my/icon3@2x.png',
+    iconActive: '/src/assets/imgs/my/icon3a@2x.png'
+  },
+  {
+    name: 'personalCenter.myDemand',
+    path: '/personal-center/demand',
+    icon: '/src/assets/imgs/my/icon4@2x.png',
+    iconActive: '/src/assets/imgs/my/icon4a@2x.png'
+  },
+  {
+    name: 'personalCenter.myOrders',
+    path: '/personal-center/orders',
+    icon: '/src/assets/imgs/my/icon5@2x.png',
+    iconActive: '/src/assets/imgs/my/icon5a@2x.png'
+  },
+  {
+    name: 'personalCenter.myInvoice',
+    path: '/personal-center/invoice',
+    icon: '/src/assets/imgs/my/icon6@2x.png',
+    iconActive: '/src/assets/imgs/my/icon6a@2x.png'
+  },
+  {
+    name: 'personalCenter.myWorkflow',
+    path: '/personal-center/workflow',
+    icon: '/src/assets/imgs/my/icon7@2x.png',
+    iconActive: '/src/assets/imgs/my/icon7a@2x.png'
+  }
+])
+const navIndex = computed(()=>{
+  switch (route.name) {
+    case 'Wallet':
+      return 0
+      break;
+    case 'MemberDetails':
+      return 1
+      break;
+    case 'Wallet':
+      return 0
+      break;
+    case 'Collection':
+      return 2
+      break;
+    case 'Demand':
+      return 3
+      break;
+    case 'Orders':
+      return 4
+      break;
+     case 'Invoice':
+      return 5
+      break;
+    case 'Workflow':
+      return 6
+      break;
+    default:
+      break;
+  }
+  return null;
+})
+
+const userInfo = ref({})//用户信息
+
+const toPath = (item: any, index: number) => {
+  if (item.path) {
+    router.push(item.path);
+  }
+};
+// 签到
+const signIn = async () => {
+  let res = await checkIn({ actionType: 1 });
+  console.log(res);
+}
+// 获取用户信息
+const getInfo = async () => {
+  let res = await getUserInfo();
+  userInfo.value = res.user;
+  console.log(res.user);
+}
+onMounted(() => {
+  getInfo()
+})
+</script>
+<style lang="scss" scoped>
+div {
+  -webkit-user-select: none;
+  /* Safari, Chrome */
+  -moz-user-select: none;
+  /* Firefox */
+  -ms-user-select: none;
+  /* IE 10+ */
+  user-select: none;
+  /* 标准语法 */
+}
+
+.personal-head {
+  border-radius: 16px;
+  padding: 24px 16px;
+  background: #FFFFFF;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+
+  .personal-head-left {
+    display: flex;
+
+    .personal-user-info {
+      margin-left: 16px;
+
+      .personal-username {
+        display: flex;
+        align-items: center;
+        font-size: 18px;
+        font-weight: bold;
+        color: #333333;
+
+        img {
+          width: 51px;
+          height: 21px;
+          margin-left: 8px;
+        }
+      }
+
+      .personal-user-list {
+        display: flex;
+        margin-top: 16px;
+        align-items: center;
+
+        .personal-user-li {
+          span {
+            color: #333333;
+            font-size: 14px;
+
+            &:first-child {
+              font-size: 28px;
+              font-weight: bold;
+              margin-right: 10px;
+            }
+          }
+        }
+
+        .personal-user-line {
+          margin: 0 16px;
+          height: 20px;
+          width: 2px;
+          background: #EBEEF5;
+        }
+      }
+    }
+  }
+
+  .personal-head-right {
+    display: flex;
+    align-items: center;
+
+    .personal-head-right-li {
+      display: flex;
+      padding: 9px 16px;
+      align-items: center;
+      margin-left: 8px;
+      // height: 32px;
+      background: #EAF0FF;
+      border-radius: 4px;
+      cursor: pointer;
+
+      &:first-child {
+        margin-left: 0;
+      }
+
+      &:last-child {
+        background: linear-gradient(270deg, #0055FE 0%, #C832FA 100%);
+
+        div {
+          color: #FFFFFF;
+        }
+      }
+
+      img {
+        width: 14px;
+        height: 14px;
+        margin-right: 4px;
+      }
+
+      div {
+        color: #2D71FF;
+        font-size: 14px;
+      }
+
+      &:hover {
+        opacity: 0.7;
+      }
+    }
+  }
+}
+
+.personal-main {
+  margin-top: 16px;
+  display: flex;
+  justify-content: space-between;
+
+  .personal-left {
+    width: 300px;
+
+    .personal-left-list {
+      background: #FFFFFF;
+      border-radius: 16px;
+      padding: 8px;
+
+      .personal-left-li {
+        height: 56px;
+        display: flex;
+        align-items: center;
+        padding: 0 8px;
+        font-size: 16px;
+        color: #333333;
+        cursor: pointer;
+        border-radius: 8px;
+
+        img {
+          width: 20px;
+          height: 20px;
+          margin-right: 4px;
+        }
+
+        &:hover {
+          background: #F5F7FF;
+        }
+      }
+
+      .active {
+        position: relative;
+        background: #EAF0FF;
+
+        &::after {
+          top: 50%;
+          transform: translateY(-50%);
+          content: '';
+          position: absolute;
+          right: 8px;
+          width: 4px;
+          height: 24px;
+          background: #2D71FF;
+          border-radius: 2px;
+        }
+
+        div {
+          color: #2D71FF;
+        }
+      }
+    }
+  }
+
+  .personal-right {
+    flex: 1;
+
+    margin-left: 16px;
+
+    .personal-right-main {
+      padding: 0 16px;
+      border-radius: 16px;
+      background: #FFFFFF;
+    }
+  }
+}
+</style>

+ 49 - 2
src/router/index.js

@@ -4,6 +4,7 @@ import CourseDetail from '../pages/CourseDetail.vue'
 import MyLearning from '../pages/MyLearning.vue'
 import MyLearningHome from '../pages/MyLearningHome.vue'
 import Layout from '@/components/Layout.vue'
+import { pa } from 'element-plus/es/locales.mjs'
 
 const routes = [
   {
@@ -119,8 +120,54 @@ const routes = [
     component: () => import('@/pages/mibiShop/mibiShop.vue'),
     meta: { title: 'route.mibiShop' }
   },
-
-
+  {
+    path: '/personal-center',
+    name: 'PersonalCenterHome',
+    component: () => import('@/pages/PersonalCenter.vue'),
+    meta: { title: 'personalCenter.personalCenter' },
+    children:[
+      {
+        path: 'wallet',
+        name: 'Wallet',
+        component: () => import('@/pages/Personal/Wallet.vue')
+      },
+      {
+        path: 'collection',
+        name: 'Collection',
+        component: () => import('@/pages/Personal/Collection.vue')
+      },
+      {
+        path: 'orders',
+        name: 'Orders',
+        component: () => import('@/pages/Personal/Orders.vue')
+      },
+      {
+        path: 'member-details',
+        name: 'MemberDetails',
+        component: () => import('@/pages/Personal/MemberDetails.vue')
+      },
+      {
+        path: 'demand',
+        name: 'Demand',
+        component: () => import('@/pages/Personal/Demand.vue')
+      },
+      {
+        path: 'invoice',
+        name: 'Invoice',
+        component: () => import('@/pages/Personal/Invoice.vue')
+      },
+      {
+        path: 'workflow',
+        name: 'Workflow',
+        component: () => import('@/pages/Personal/Workflow.vue')
+      }
+    ]
+  },
+  {
+    path:'/member',
+    name:'Member',
+    component: () => import('@/pages/Member.vue')
+  },
 
 
 

+ 10 - 1
src/styles/index.scss

@@ -36,8 +36,11 @@ H3,
 H4,
 H5,
 H6,
-P {
+P,
+ul,
+li {
   margin: 0;
+	padding: 0;
 }
 
 body ,htm{
@@ -51,6 +54,9 @@ body{
 	background: url('@/assets/imgs/bg_2.png') no-repeat center center fixed;
 	background-size: 100% 100%;
 }
+ul,li {
+	list-style: none;
+}
 
 .detail_right{
 	width: 410px;
@@ -215,6 +221,9 @@ wx-image{
 .mt5 {
 	margin-top: 5px;
 }
+.mt4 {
+	margin-top: 4px;
+}
 .mb20 {
 	margin-bottom: 20px;
 }