Browse Source

feat: 项目初始化完善中

sunxiao 7 months ago
parent
commit
41b5a365ee

+ 1 - 0
src/App.vue

@@ -14,4 +14,5 @@ export default {
 
 <style>
 /*每个页面公共css */
+@import '@/assets/style/common.scss';
 </style>

+ 12 - 0
src/api/chat.js

@@ -0,0 +1,12 @@
+
+import { http } from '@/utils/https';
+
+export const chatApi = {
+  /**
+   * 推荐问答列表
+   */
+  getWelcomeRecommend: data => http({
+    method: 'GET',
+    url: '/front/bigModel/home/recommendQAList/' + data
+  }),
+}

+ 0 - 1
src/api/login.js

@@ -1,4 +1,3 @@
-
 import { http } from '@/utils/https';
 
 export const userApi = {

+ 11 - 0
src/assets/style/common.scss

@@ -0,0 +1,11 @@
+.nav-btn_back {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 80rpx;
+  padding: 10rpx 0;
+}
+
+.chat-container {
+  padding: 0 20rpx;
+}

BIN
src/assets/test.png


+ 10 - 0
src/assets/test.svg

@@ -0,0 +1,10 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="375" height="812" viewBox="0 0 375 812" fill="linear-gradient(180deg, #EEF4FF 0%, #F5FBFE 23.71%);
+">
+<path d="M0 0H375V812H0V0Z" fill="url(#paint0_linear_2395_1305)"/>
+<defs>
+<linearGradient id="paint0_linear_2395_1305" x1="187.5" y1="0" x2="187.5" y2="812" gradientUnits="userSpaceOnUse">
+<stop stop-color="#EEF4FF"/>
+<stop offset="0.237104" stop-color="#F5FBFE"/>
+</linearGradient>
+</defs>
+</svg>

+ 42 - 0
src/components/TheSvgIcon.vue

@@ -0,0 +1,42 @@
+<script setup>
+import { computed } from 'vue';
+
+const props = defineProps({
+  src: {
+    type: String,
+    default: ""
+  },
+  size: {
+    type: String,
+    default: "40"
+  },
+})
+
+const emits = defineEmits(['on-click']);
+
+const FILE_URL = "https://static.fuxicarbon.com/bigModel/wechat/tools/"
+
+const url = computed(() => FILE_URL + props.src + '.svg');
+
+const emitEvent = () => emits('on-click');
+</script>
+
+<template>
+  <view class="img-container" :style="{ width: size + 'rpx', height: size + 'rpx' }" @click="emitEvent">
+    <image :src="url" class="image"></image>
+  </view>
+</template>
+
+<style lang="scss" scoped>
+.img-container {
+  flex-shrink: 1;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+
+  .image {
+    width: 100%;
+    height: 100%;
+  }
+}
+</style>

+ 70 - 0
src/components/chat/ChatAnswer.vue

@@ -0,0 +1,70 @@
+<script setup>
+import { ref } from 'vue';
+</script>
+
+<template>
+  <view class="answer-container">
+    <view class="answer-inner">
+      <view class="markdown-wrap">
+        污水首先通过粗格栅去除较大的悬浮物和固体杂质,随后通过细格
+      </view>
+      <view class="tools-wrap">
+        <view class="btn-stream">
+          <TheSvgIcon class="icon" src="icon-refresh" size="26"></TheSvgIcon>
+          <text>重新生成</text>
+        </view>
+        <view class="btn-group">
+          <TheSvgIcon class="icon" src="icon-like-yes" size="28"></TheSvgIcon>
+          <view class="line"></view>
+          <TheSvgIcon class="icon" src="icon-like-no" size="28"></TheSvgIcon>
+          <view class="line"></view>
+          <TheSvgIcon class="icon" src="icon-like-copy" size="28"></TheSvgIcon>
+        </view>
+      </view>
+    </view>
+  </view>
+</template>
+
+<style lang="scss" scoped>
+.answer-container {
+  padding-right: 64rpx;
+
+  .answer-inner {
+    padding: 24rpx;
+    border-radius: 4rpx 30rpx 30rpx 30rpx;
+    background: #fff;
+
+    .markdown-wrap {}
+
+    .tools-wrap {
+      padding-top: 20rpx;
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      font-size: 24rpx;
+      color: #7B909C;
+
+      .btn-stream,
+      .btn-group {
+        display: flex;
+        align-items: center;
+      }
+
+      .btn-stream {
+        .icon {
+          margin-right: 8rpx;
+        }
+      }
+
+      .btn-group {
+        .line {
+          width: 1px;
+          height: 16rpx;
+          margin: 0 32rpx;
+          background: #CFD3D9;
+        }
+      }
+    }
+  }
+}
+</style>

+ 32 - 0
src/components/chat/ChatAsk.vue

@@ -0,0 +1,32 @@
+<script setup>
+import { ref } from 'vue';
+</script>
+
+<template>
+  <view class="ask-container">
+    <view class="ask-inner">
+      <view class="ask-content">
+        污水首先通过粗格栅去除较大的悬浮物和固体杂质,随后通过细格 
+      </view>
+    </view>
+  </view>
+</template>
+
+<style lang="scss" scoped>
+.ask-container {
+  // padding-left: 64rpx;
+  margin-bottom: 32rpx;
+}
+.ask-inner {
+  display: flex;
+  justify-content: flex-end;
+  font-size: 28rpx;
+  color: #fff;
+  .ask-content {
+    display: inline-flex;
+    padding: 20rpx 24rpx;
+    border-radius: 30rpx 30rpx 4rpx 30rpx;
+    background: linear-gradient(88deg, #2A67F8 4.95%, #4892FF 93.07%);
+  }
+}
+</style>

+ 10 - 0
src/components/chat/ChatScrollView.vue

@@ -0,0 +1,10 @@
+<script setup>
+
+</script>
+
+<template>
+  
+</template>
+
+<style lang="scss" scoped>
+</style>

+ 114 - 0
src/components/chat/ChatWelcome.vue

@@ -0,0 +1,114 @@
+<script setup>
+defineProps({
+  title: {
+    type: String,
+    default: ""
+  },
+  cardTitle: {
+    type: String,
+    default: ""
+  },
+  subTitle: {
+    type: Array,
+    default: () => []
+  },
+  cardContent: {
+    type: Array,
+    default: () => []
+  }
+})
+</script>
+
+<template>
+  <view class="chat-welcome">
+    <view class="weclome-inner">
+      <TheSvgIcon src="icon-logo" size="136"></TheSvgIcon>
+      <Text class="title">{{ title }}</Text>
+      <Text class="desc" v-for="item, index in subTitle" :key="index">{{ item }}</Text>
+    </view>
+
+    <view class="recommend-inner">
+      <view class="question-card">
+        <text class="title">{{ cardTitle }}</text>
+        <view class="list">
+          <view class="item" v-for="item in cardContent" :key="item.id">
+            <text class="text">{{ item.question }}</text>
+            <TheSvgIcon src="icon-right-arrow" size="28"></TheSvgIcon>
+          </view>
+        </view>
+      </view>
+    </view>
+  </view>
+</template>
+
+<style lang="scss" scoped>
+.chat-welcome {
+  .weclome-inner {
+    display: flex;
+    align-items: center;
+    flex-flow: column;
+    padding: 0rpx 0 72rpx 0;
+    text-align: center;
+
+    .title {
+      margin: 16rpx 0;
+      background: linear-gradient(90deg, #5C6883 0%, #212121 100%);
+      background-clip: text;
+      font-weight: bold;
+      font-size: 36rpx;
+      -webkit-background-clip: text;
+      -webkit-text-fill-color: transparent;
+    }
+
+    .desc {
+      font-size: 24rpx;
+      line-height: 44rpx;
+      color: #7B909C;
+    }
+  }
+
+  .recommend-inner {
+    padding: 0 64rpx 0 22rpx;
+
+    .question-card {
+      padding: 40rpx 34rpx 20rpx 34rpx;
+      border-radius: 4rpx 30rpx 30rpx 30rpx;
+      background: #fff;
+      font-size: 28rpx;
+      font-weight: bold;
+
+      .title {
+        background: var(--, linear-gradient(92deg, #5ABBF2 12.24%, #2454FF 63.2%));
+        background-clip: text;
+        -webkit-background-clip: text;
+        -webkit-text-fill-color: transparent;
+      }
+
+      .list {
+        color: #212121;
+
+        .item {
+          display: flex;
+          justify-content: space-between;
+          align-items: center;
+          padding: 32rpx 0;
+
+          .text {
+            padding-right: 60rpx;
+            line-height: 48rpx;
+            overflow: hidden;
+            text-overflow: ellipsis;
+            display: -webkit-box;
+            -webkit-line-clamp: 2; 
+            -webkit-box-orient: vertical;
+          }
+
+          &:not(:last-child) {
+            border-bottom: 1px solid #F6F6F6;
+          }
+        }
+      }
+    }
+  }
+}
+</style>

+ 4 - 2
src/components/TheNavBar.vue → src/components/layout/BaseNavBar.vue

@@ -9,9 +9,11 @@ defineProps({
 
 <template>
   <view class="nav-bar-container">
-    <TheStatusBar></TheStatusBar>
-    <uni-nav-bar :border="false" backgroundColor="rgba(0,0,0,0)">
+    <BaseStatusBar></BaseStatusBar>
+    <uni-nav-bar :border="false" backgroundColor="rgba(0,0,0,0)" leftWidth="200rpx" rightWidth="200rpx">
+      <template #left><slot></slot></template>
       <view class="title">{{ titleText }}</view>
+      <template #right><slot name="right"></slot></template>
     </uni-nav-bar>
   </view>
 </template>

+ 115 - 0
src/components/layout/BasePublicLayout.vue

@@ -0,0 +1,115 @@
+<script setup>
+import { ref, onMounted, getCurrentInstance, watch } from 'vue';
+
+const scrollTops = ref(0);
+const scrollView = ref(null);
+const scrollViewRef = ref(null);
+const scrollIntoView = ref(null);
+const instance = getCurrentInstance();
+
+const redColor = ref('red')
+
+const props = defineProps({
+  bgColor: {
+    type: String,
+    default: 'linear-gradient(240deg, #dce8fd 0%, #f6fbfe 100%)'
+  },
+  isFooter: {
+    type: Boolean,
+    default: true
+  },
+  nums: {
+    type: Number,
+    default: 0
+  }
+});
+
+watch(()=> props.nums, () => {
+  // console.log("watch");
+}, { immediate: true, deep: true })
+
+const test = () => {
+  const domQuery = uni.createSelectorQuery();
+  domQuery.in(instance).select('.scroll-view').boundingClientRect();
+  domQuery.in(instance).select('.scroll-content').boundingClientRect();
+
+  domQuery.exec(res => {
+    console.log("res", res);
+
+    const scrollViewHeight = res[0].height
+    const scrollContentHeight = res[1].height
+ 
+    console.log( res[1].bottom - res[0].bottom );
+
+    if (scrollContentHeight > scrollViewHeight) {
+      const scrollTop = scrollContentHeight - scrollViewHeight
+      console.log("scrollTop", scrollTop);
+
+      // if ( scrollContentHeight - scrollTop - scrollViewHeight <= 100 ) {
+      //   console.log( scrollContentHeight );
+      //   console.log( scrollTop );
+      //   console.log( scrollViewHeight );
+      //   console.log( "没有到底", scrollContentHeight - scrollTop - scrollViewHeight );
+      // } 
+
+      // scrollTops.value = scrollTop
+    }
+  })
+}
+const onScroll = (data) => {
+  // console.log("scroll", data);
+  // test()
+}
+
+onMounted(() => {
+  // setTimeout(() => {
+  //   console.log("触底了");
+  //   scrollIntoView.value = 'scroll-into-view'
+  // }, 3000)
+})
+
+</script>
+
+<template>
+  <view class="layout_container" :style="{ background: bgColor }">
+    <view class="header">
+      <slot name="header"></slot>
+    </view>
+    <scroll-view
+      class="scroll-view"
+      ref="scrollViewRef"
+      scroll-y
+      :scrollTop="scrollTops"
+      :scroll-with-animation="true"
+      :scroll-into-view="scrollIntoView"
+      @scroll="onScroll"
+    >
+      <view class="scroll-content">
+        <slot name="content"></slot>
+      </view>
+    </scroll-view>
+    <view class="footer" v-if="isFooter">
+
+      <!-- 这里需拆分出去 -->
+      <BaseTabBar></BaseTabBar>
+    </view>
+  </view>
+</template>
+
+<style lang="scss" scoped>
+.layout_container {
+  display: flex;
+  flex-flow: column;
+  justify-content: space-between;
+  height: 100vh;
+
+  .scroll-view {
+    flex: 1;
+    overflow: hidden;
+
+    .scroll-content {
+      padding-top: 56rpx;
+    }
+  }
+}
+</style>

+ 0 - 0
src/components/TheStatusBar.vue → src/components/layout/BaseStatusBar.vue


+ 113 - 0
src/components/layout/BaseTabBar.vue

@@ -0,0 +1,113 @@
+<script setup>
+import { ref } from 'vue';
+import { storeToRefs } from 'pinia';
+
+import { useAppStore } from '@/stores/modules/appStore';
+
+const appStore = useAppStore();
+const { onChangeActive } = appStore;
+const { tabBarData, activeIndex } = storeToRefs(appStore);
+</script>
+
+<template>
+  <view class="tab-bar-container">
+    <view :class="['tab-bar-inner', {'workbench-bg_active': activeIndex == 2}]">
+      <view class="tab-bar_list">
+        <view class="tab-bar_item" v-for="item, index in tabBarData" :key="item.text" @click="onChangeActive(index)">
+          <template>
+            <view :class="['icon', { btn: item.isSpecial }]">
+              <image
+                :src="activeIndex === index ? item.selectedIconPath : item.iconPath"
+                class="image"
+              ></image>
+              <view class="round-tips" v-if="index == 3"></view>
+            </view>
+            <view
+              class="text"
+              :style="{color: activeIndex === index ? '#2454FF' : '#4F4F4F'}"
+              v-if="!item.isSpecial"
+            >{{ item.text }}</view>
+          </template>
+        </view>
+      </view>
+    </view>
+  </view>
+</template>
+
+<style lang="scss" scoped>
+.tab-bar-container {
+  border-bottom: env(safe-area-inset-bottom) solid #fff;
+
+  .tab-bar-inner {
+    width: 100%;
+    height: 116rpx;
+    background: #fff;
+    font-size: 24rpx;
+  
+    .tab-bar_list {
+      display: flex;
+      align-items: center;
+      justify-content: space-around;
+      height: 100%;
+  
+      .tab-bar_item {
+        position: relative;
+        width: 20%;
+        display: flex;
+        flex-flow: column;
+        align-items: center;
+        transition: all 1.3s;
+  
+        .icon {
+          position: relative;
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          width: 48rpx;
+          height: 48rpx;
+        }
+  
+        .text {
+          padding-top: 8rpx;
+        }
+  
+        .image {
+          width: 48rpx;
+          height: 48rpx;
+        }
+  
+        .btn {
+          position: absolute;
+          top: -20rpx;
+          left: 50%;
+          display: flex;
+          justify-content: center;
+          align-items: center;
+          width: 110rpx;
+          height: 110rpx;
+          transform: translate(-50%, -50%);
+          background: #2454FF;
+          border-radius: 50%;
+          filter: drop-shadow(0px 6px 16px rgba(59, 69, 239, 0.60));
+        }
+
+        .round-tips {
+          position: absolute;
+          top: 0rpx;
+          right: 12rpx;
+          width: 12rpx;
+          height: 12rpx;
+          border-radius: 100%;
+          background: #FD5D4D;
+        }
+      }
+    }
+  }
+  
+  .workbench-bg_active {
+    transition: all .2s;
+    background: url("https://static.fuxicarbon.com/bigModel/wechat/layout/subtract.svg") no-repeat;
+    background-size: 100% 100%;
+  }
+}
+</style>

+ 16 - 0
src/composables/useRecommend.js

@@ -0,0 +1,16 @@
+import { ref, onMounted } from 'vue';
+import { chatApi } from '@/api/chat';
+
+export const useRecommend = ({ type }) => {
+
+  const recommendList = ref([]);
+
+  onMounted(async () => {
+    const { data } = await chatApi.getWelcomeRecommend(type);
+    recommendList.value = data;
+  })
+
+  return {
+    recommendList
+  }
+}

+ 70 - 28
src/pages.json

@@ -1,33 +1,75 @@
 {
-	"pages": [
-		{
-			"path": "pages/login/index",
-			"style": {
+  "pages": [
+    {
+      "path": "pages/chat/chatView",
+      "style": {
+        "navigationStyle": "custom",
+        "navigationBarTitleText": "对话窗口",
+        "disableScroll": true
+      }
+    },
+    {
+      "path": "pages/chat/index",
+      "style": {
+        "navigationStyle": "custom",
+        "navigationBarTitleText": "专家问答",
+        "disableScroll": true
+      }
+    },
+    {
+      "path": "pages/home/index",
+      "style": {
+        "navigationStyle": "custom",
+        "navigationBarTitleText": "首页",
+        "disableScroll": true
+      }
+    },
+    {
+      "path": "pages/workbench/index",
+      "style": {
+        "navigationStyle": "custom",
+        "navigationBarTitleText": "工作台",
+        "disableScroll": true
+      }
+    },
+    {
+      "path": "pages/message/index",
+      "style": {
+        "navigationStyle": "custom",
+        "navigationBarTitleText": "消息",
+        "disableScroll": true
+      }
+    },
+    {
+      "path": "pages/my/index",
+      "style": {
+        "navigationStyle": "custom",
+        "navigationBarTitleText": "我的",
+        "disableScroll": true
+      }
+    },
+    {
+      "path": "pages/login/index",
+      "style": {
         "disableScroll": true,
         "navigationStyle": "custom",
         "navigationBarTitleText": "登录"
-			}
-		},
-		{
-			"path": "pages/home/index",
-			"style": {
-        "navigationStyle": "custom",
-				"navigationBarTitleText": "首页"
-			}
-		}
-	],
-	"globalStyle": {
-		"navigationBarTextStyle": "black",
-		"navigationBarTitleText": "uni-app",
-		"navigationBarBackgroundColor": "#F8F8F8",
-		"backgroundColor": "#F8F8F8"
-	},
-	"easycom": {
-		"autoscan": true,
-		"custom": {
-			"^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue",
+      }
+    }
+  ],
+  "globalStyle": {
+    "navigationBarTextStyle": "black",
+    "navigationBarTitleText": "uni-app",
+    "navigationBarBackgroundColor": "#F8F8F8",
+    "backgroundColor": "#F8F8F8"
+  },
+  "easycom": {
+    "autoscan": true,
+    "custom": {
+      "^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue",
       "^The(.*)": "@/components/The$1.vue",
-      "^La(.*)": "@/components/layout/La$1.vue"
-		}
-	}
-}
+      "^Base(.*)": "@/components/layout/Base$1.vue",
+      "^Chat(.*)": "@/components/chat/Chat$1.vue"
+    }
+  }
+}

+ 66 - 0
src/pages/chat/chatView.vue

@@ -0,0 +1,66 @@
+<script setup>
+import { ref } from 'vue';
+
+const val = ref('');
+
+</script>
+
+<template>
+  <BasePublicLayout :is-footer="false">
+    <template #header>
+      <BaseNavBar title-text="专家问答">
+        <view class="nav-btn_back">
+          <TheSvgIcon class="icon" src="icon-back" size="40"></TheSvgIcon>
+        </view>
+      </BaseNavBar>
+    </template>
+    <template #content>
+      <view class="chat-container">
+        <ChatAsk></ChatAsk>
+        <ChatAnswer></ChatAnswer>
+        <view class="chat-inp-container">
+          TheSvgIcon
+          <textarea v-model="val" auto-height :maxlength="1000"></textarea>
+        </view>
+      </view>
+    </template>
+    <!-- auto-height -->
+    <template #footer>123123</template>
+  </BasePublicLayout>
+</template>
+
+<style lang="scss" scoped>
+.chat-inp-container {
+  width: 60%;
+  // height: 26px;
+  padding: 28rpx;
+  border-radius: 104rpx;
+  background: #FFF;
+  box-sizing: content-box;
+  box-shadow: 0px 4px 8px 1px rgba(192, 192, 192, 0.25);
+
+  textarea {
+
+    border: 1px solid rgb(201, 201, 201); // 边框
+
+    width: 100%;
+
+    font-size: 28rpx; // 设置字体大小和行高一样解决内部出现滚动条问题
+
+    line-height: 28rpx;
+    
+    padding: 0;
+
+    // min-height: 20px;
+
+    max-height: 300rpx;
+  }
+
+  // position: fixed;
+  // bottom: 0;
+  // left: 0;
+  // right: 0;
+  // height: 100rpx;
+  // background-color: #fff;
+}
+</style>

+ 65 - 0
src/pages/chat/index.vue

@@ -0,0 +1,65 @@
+<script setup>
+import { onMounted, ref } from 'vue';
+import { useUserStore } from '@/stores/modules/userStore';
+import { useRecommend } from '@/composables/useRecommend';
+
+const userStore = useUserStore();
+
+const { recommendList } = useRecommend({ type: 0 });
+
+
+const jumpChatView = () => {
+  console.log("执行了");
+  uni.navigateTo({url: '/pages/chat/chatView'});
+}
+
+onMounted(() => {
+  // setInterval(item => {
+  //   num.value = num.value + 1;
+  //   console.log( num.value );
+  // }, 1000)
+})
+
+</script>
+
+<template>
+  <view class="home-viewport">
+    <BasePublicLayout>
+      <template #header>
+        <BaseNavBar titleText="专家问答">
+          <view class="tools-list">
+            <TheSvgIcon class="icon" src="icon-nav-history" size="40" @on-click="jumpChatView"></TheSvgIcon>
+            <TheSvgIcon class="icon" src="icon-nav-add" size="40"></TheSvgIcon>
+            <TheSvgIcon class="icon" src="icon-nav-voice" size="40"></TheSvgIcon>
+          </view>
+        </BaseNavBar>
+      </template>
+      <template #content>
+        <!-- <ChatAsk></ChatAsk>
+        <ChatAnswer></ChatAnswer> -->
+        <ChatWelcome
+          title="您好,我是LibraAI专家问答"
+          card-title="您可以试着问我:"
+          :sub-title="[
+            '期待与您一同规划和完成未来的工作',
+            '有任何重点或需讨论的事项,随时告诉我'
+          ]"
+          :card-content="recommendList"
+        ></ChatWelcome>
+      </template>
+    </BasePublicLayout>
+  </view>
+
+</template>
+
+<style lang="scss" scoped>
+.home-viewport {
+  .tools-list {
+    display: flex;
+    align-items: center;
+    & .icon:nth-child(2) {
+      margin: 0 20rpx;
+    }
+  }
+}
+</style>

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

@@ -1,5 +1,9 @@
 <template>
 
-  这个是首页
+  <BasePublicLayout>
+    <template #content>
+      这是home
+    </template>
+  </BasePublicLayout>
 
 </template>

+ 6 - 5
src/pages/login/index.vue

@@ -4,7 +4,7 @@ import { userApi } from '@/api/login';
 import { useUserStore } from '@/stores/modules/userStore';
 
 const REMOTE_PATH = {
-  logo: 'https://static.fuxicarbon.com/bigModel/wechat/login/img-desc.png',
+  logo    : 'https://static.fuxicarbon.com/bigModel/wechat/login/img-desc.png',
   username: 'https://static.fuxicarbon.com/bigModel/wechat/login/icon-username.png',
   password: 'https://static.fuxicarbon.com/bigModel/wechat/login/icon-password.png'
 }
@@ -14,8 +14,9 @@ const userStore = useUserStore();
 const showPasswordIcon = ref(false);
 const loading = ref(false);
 const loginFormData = ref({
-  username: 'admin',
-  password: 'admin123'
+  username: 'test1',
+  password: 'admin123',
+  type: 0
 });
 
 const handleSubmit = async () => {
@@ -32,7 +33,7 @@ const handleSubmit = async () => {
   loading.value = true;
 
   try {
-    const { token } = await userApi.postLogin({ username, password });
+    const { token } = await userApi.postLogin({ username, password, type: 0 });
 
     userStore.setUserInfo({ token });
 
@@ -53,7 +54,7 @@ const handleSubmit = async () => {
 
 <template>
   <view class="login-viewport">
-    <TheNavBar title-text="登录" class="nav-bar"></TheNavBar>
+    <BaseNavBar title-text="登录" class="nav-bar"></BaseNavBar>
     <view class="login-content">
       <view class="logo-inner">
         <image :src="REMOTE_PATH.logo" class="img-desc"></image>

+ 7 - 0
src/pages/message/index.vue

@@ -0,0 +1,7 @@
+<template>
+  <BasePublicLayout>
+    <template #content>
+      消息
+    </template>
+  </BasePublicLayout>
+</template>

+ 7 - 0
src/pages/my/index.vue

@@ -0,0 +1,7 @@
+<template>
+  <BasePublicLayout>
+    <template #content>
+      我的
+    </template>
+  </BasePublicLayout>
+</template>

+ 5 - 0
src/pages/workbench/index.vue

@@ -0,0 +1,5 @@
+<template>
+  <BasePublicLayout>
+    <template #content>工作台</template>
+  </BasePublicLayout>
+</template>

+ 65 - 0
src/stores/modules/appStore.js

@@ -0,0 +1,65 @@
+import { defineStore } from "pinia";
+import { ref } from "vue";
+
+const sourceData = [
+  {
+    pagePath: "/pages/home/index",
+    iconPath: "https://static.fuxicarbon.com/bigModel/wechat/layout/icon-home-default.png",
+    selectedIconPath: "https://static.fuxicarbon.com/bigModel/wechat/layout/icon-home-active.png",
+    isSpecial: false,
+    text: "首页",
+  },
+  {
+    pagePath: "/pages/chat/index",
+    iconPath: "https://static.fuxicarbon.com/bigModel/wechat/layout/icon-answer-default.png",
+    selectedIconPath: "https://static.fuxicarbon.com/bigModel/wechat/layout/icon-answer-active.png",
+    isSpecial: false,
+    text: "专家问答",
+  },
+  {
+    pagePath: "/pages/workbench/index",
+    iconPath: "https://static.fuxicarbon.com/bigModel/wechat/layout/icon-workbench-default.png",
+    selectedIconPath: "https://static.fuxicarbon.com/bigModel/wechat/layout/icon-workbench-default.png",
+    isSpecial: true,
+    text: "工作台",
+  },
+  {
+    pagePath: "/pages/message/index",
+    iconPath: "https://static.fuxicarbon.com/bigModel/wechat/layout/icon-msg-default.png",
+    selectedIconPath: "https://static.fuxicarbon.com/bigModel/wechat/layout/icon-msg-active.png",
+    isSpecial: false,
+    text: "消息",
+  },
+  {
+    pagePath: "/pages/my/index",
+    iconPath: "https://static.fuxicarbon.com/bigModel/wechat/layout/icon-my-default.png",
+    selectedIconPath: "https://static.fuxicarbon.com/bigModel/wechat/layout/icon-my-active.png",
+    isSpecial: false,
+    text: "我的",
+  },
+];
+
+export const useAppStore = defineStore(
+  "app",
+  () => {
+    const tabBarData = ref(sourceData);
+    const activeIndex = ref(1);
+
+    const onChangeActive = (index) => {
+      const routes = getCurrentPages();
+      const curRoute = routes[routes.length - 1].route;
+      const url = tabBarData.value[index].pagePath;
+
+      if ( curRoute != url.substring(1) ) {
+        activeIndex.value = index;
+        uni.redirectTo({ url });
+      }
+    };
+
+    return {
+      tabBarData,
+      activeIndex,
+      onChangeActive
+    };
+  },
+);

+ 0 - 15
src/stores/modules/appStrore.js

@@ -1,15 +0,0 @@
-import { defineStore } from "pinia";
-import { ref } from "vue";
-
-export const useAppStore = defineStore("app", () => {}, {
-  persist: {
-    storage: {
-      setItem(key, value) {
-        uni.setStorageSync(key, value);
-      },
-      getItem(key) {
-        return uni.getStorageSync(key);
-      },
-    },
-  },
-});

+ 2 - 3
src/utils/https.js

@@ -10,9 +10,8 @@ const httpInterceptor = {
     if (!options.url.startsWith('http')) {
       options.url = baseURL + options.url
     }
-    options.timeout = 3000
-    options.header = {...options.header}
-
+    options.timeout = 3000;
+    options.header = {...options.header};
     const token = userStore.userInfo?.token;
     token && (options.header.Authorization = 'Bearer ' + token);
   },