Parcourir la source

init: uni-app x 项目基础架构与 TabBar

wangguoyu il y a 3 semaines
commit
644659796f
14 fichiers modifiés avec 396 ajouts et 0 suppressions
  1. 5 0
      .gitignore
  2. 22 0
      App.uvue
  3. 12 0
      api/user.uts
  4. 18 0
      common/env.uts
  5. 9 0
      main.uts
  6. 27 0
      manifest.json
  7. 9 0
      package.json
  8. 48 0
      pages.json
  9. 26 0
      pages/category/category.uvue
  10. 61 0
      pages/index/index.uvue
  11. 26 0
      pages/mine/mine.uvue
  12. 45 0
      store/user.uts
  13. 71 0
      utils/request.uts
  14. 17 0
      utils/storage.uts

+ 5 - 0
.gitignore

@@ -0,0 +1,5 @@
+node_modules/
+unpackage/
+.DS_Store
+.idea/
+.hbuilderx/

+ 22 - 0
App.uvue

@@ -0,0 +1,22 @@
+<script lang="uts">
+import { initStore } from '@/store/user.uts'
+
+export default {
+  onLaunch: function () {
+    initStore()
+    console.log('App Launch')
+  },
+  onShow: function () {
+    console.log('App Show')
+  },
+  onHide: function () {
+    console.log('App Hide')
+  }
+}
+</script>
+
+<style>
+page {
+  background-color: #f5f5f5;
+}
+</style>

+ 12 - 0
api/user.uts

@@ -0,0 +1,12 @@
+import { request, get, post } from '@/utils/request.uts'
+
+export function login(username : string, password : string) : Promise<UTSJSONObject> {
+  const data : UTSJSONObject = {}
+  data['username'] = username
+  data['password'] = password
+  return post<UTSJSONObject>('/auth/login', data)
+}
+
+export function getUserProfile() : Promise<UTSJSONObject> {
+  return get<UTSJSONObject>('/user/profile')
+}

+ 18 - 0
common/env.uts

@@ -0,0 +1,18 @@
+export type EnvConfig = {
+  baseUrl : string
+  name : string
+}
+
+const DEV : EnvConfig = {
+  name: 'dev',
+  baseUrl: 'https://dev-api.example.com'
+}
+
+const PROD : EnvConfig = {
+  name: 'prod',
+  baseUrl: 'https://api.example.com'
+}
+
+export const env : EnvConfig = DEV
+
+export const TIMEOUT : number = 15000

+ 9 - 0
main.uts

@@ -0,0 +1,9 @@
+import App from './App.uvue'
+import { createSSRApp } from 'vue'
+
+export function createApp() {
+  const app = createSSRApp(App)
+  return {
+    app
+  }
+}

+ 27 - 0
manifest.json

@@ -0,0 +1,27 @@
+{
+  "name": "uniProjectX",
+  "appid": "",
+  "description": "uni-app x 项目",
+  "versionName": "1.0.0",
+  "versionCode": "100",
+  "transformPx": false,
+  "app": {
+    "defaultLanguage": "zh-Hans",
+    "usingComponents": true,
+    "distribute": {
+      "icons": {
+        "android": {},
+        "ios": {}
+      }
+    }
+  },
+  "uni-app-x": {
+    "uvue": {
+      "compilerOptions": {}
+    }
+  },
+  "uniStatistics": {
+    "enable": false
+  },
+  "vueVersion": "3"
+}

+ 9 - 0
package.json

@@ -0,0 +1,9 @@
+{
+  "name": "uniProjectX",
+  "version": "1.0.0",
+  "description": "uni-app x 项目",
+  "private": true,
+  "uni-app-x": {
+    "flex-direction": "column"
+  }
+}

+ 48 - 0
pages.json

@@ -0,0 +1,48 @@
+{
+  "pages": [
+    {
+      "path": "pages/index/index",
+      "style": {
+        "navigationBarTitleText": "首页"
+      }
+    },
+    {
+      "path": "pages/category/category",
+      "style": {
+        "navigationBarTitleText": "分类"
+      }
+    },
+    {
+      "path": "pages/mine/mine",
+      "style": {
+        "navigationBarTitleText": "我的"
+      }
+    }
+  ],
+  "tabBar": {
+    "color": "#8F8F8F",
+    "selectedColor": "#007AFF",
+    "backgroundColor": "#FFFFFF",
+    "borderStyle": "black",
+    "list": [
+      {
+        "pagePath": "pages/index/index",
+        "text": "首页"
+      },
+      {
+        "pagePath": "pages/category/category",
+        "text": "分类"
+      },
+      {
+        "pagePath": "pages/mine/mine",
+        "text": "我的"
+      }
+    ]
+  },
+  "globalStyle": {
+    "navigationBarTextStyle": "black",
+    "navigationBarTitleText": "uniProjectX",
+    "navigationBarBackgroundColor": "#FFFFFF",
+    "backgroundColor": "#F5F5F5"
+  }
+}

+ 26 - 0
pages/category/category.uvue

@@ -0,0 +1,26 @@
+<template>
+  <view class="page">
+    <text class="title">分类</text>
+  </view>
+</template>
+
+<script lang="uts">
+export default {
+  data() {
+    return {}
+  }
+}
+</script>
+
+<style>
+.page {
+  flex: 1;
+  padding: 16px;
+  align-items: center;
+  justify-content: center;
+}
+.title {
+  font-size: 20px;
+  color: #333333;
+}
+</style>

+ 61 - 0
pages/index/index.uvue

@@ -0,0 +1,61 @@
+<template>
+  <view class="page">
+    <view class="header">
+      <text class="title">首页</text>
+      <text class="subtitle">uni-app x 项目已就绪</text>
+    </view>
+    <view class="card">
+      <text class="card-title">基础架构</text>
+      <text class="card-item">· pages / components / api / store / utils</text>
+      <text class="card-item">· TabBar 三页已配置</text>
+      <text class="card-item">· 请求封装见 utils/request.uts</text>
+    </view>
+  </view>
+</template>
+
+<script lang="uts">
+export default {
+  data() {
+    return {}
+  },
+  onLoad() {
+    console.log('index onLoad')
+  }
+}
+</script>
+
+<style>
+.page {
+  flex: 1;
+  padding: 16px;
+}
+.header {
+  padding: 24px 0;
+}
+.title {
+  font-size: 24px;
+  font-weight: bold;
+  color: #333333;
+}
+.subtitle {
+  margin-top: 8px;
+  font-size: 14px;
+  color: #999999;
+}
+.card {
+  padding: 16px;
+  background-color: #ffffff;
+  border-radius: 8px;
+}
+.card-title {
+  font-size: 16px;
+  font-weight: bold;
+  color: #333333;
+  margin-bottom: 12px;
+}
+.card-item {
+  font-size: 14px;
+  color: #666666;
+  line-height: 26px;
+}
+</style>

+ 26 - 0
pages/mine/mine.uvue

@@ -0,0 +1,26 @@
+<template>
+  <view class="page">
+    <text class="title">我的</text>
+  </view>
+</template>
+
+<script lang="uts">
+export default {
+  data() {
+    return {}
+  }
+}
+</script>
+
+<style>
+.page {
+  flex: 1;
+  padding: 16px;
+  align-items: center;
+  justify-content: center;
+}
+.title {
+  font-size: 20px;
+  color: #333333;
+}
+</style>

+ 45 - 0
store/user.uts

@@ -0,0 +1,45 @@
+import { reactive } from 'vue'
+
+export type UserInfo = {
+  id : string
+  nickname : string
+  avatar : string
+}
+
+export type UserState = {
+  token : string
+  userInfo : UserInfo | null
+}
+
+export const userStore = reactive({
+  token: '',
+  userInfo: null
+} as UserState) as UserState
+
+export function setToken(token : string) {
+  userStore.token = token
+  uni.setStorageSync('token', token)
+}
+
+export function setUserInfo(info : UserInfo | null) {
+  userStore.userInfo = info
+  uni.setStorageSync('userInfo', info)
+}
+
+export function logout() {
+  userStore.token = ''
+  userStore.userInfo = null
+  uni.removeStorageSync('token')
+  uni.removeStorageSync('userInfo')
+}
+
+export function initStore() {
+  const token = uni.getStorageSync('token')
+  if (token != null) {
+    userStore.token = token as string
+  }
+  const info = uni.getStorageSync('userInfo')
+  if (info != null) {
+    userStore.userInfo = info as UserInfo
+  }
+}

+ 71 - 0
utils/request.uts

@@ -0,0 +1,71 @@
+import { env, TIMEOUT } from '@/common/env.uts'
+
+export type ApiResponse<T> = {
+  code : number
+  message : string
+  data : T | null
+}
+
+export type RequestOptions = {
+  url : string
+  method ?: string
+  data ?: UTSJSONObject | null
+  header ?: UTSJSONObject | null
+  showLoading ?: boolean
+}
+
+function getToken() : string {
+  const token = uni.getStorageSync('token')
+  if (token == null) return ''
+  return token as string
+}
+
+export function request<T>(options : RequestOptions) : Promise<T> {
+  return new Promise<T>((resolve, reject) => {
+    const header : UTSJSONObject = options.header ?? {}
+    header['Content-Type'] = 'application/json'
+    const token = getToken()
+    if (token.length > 0) {
+      header['Authorization'] = 'Bearer ' + token
+    }
+
+    uni.request({
+      url: env.baseUrl + options.url,
+      method: options.method ?? 'GET',
+      data: options.data,
+      header: header,
+      timeout: TIMEOUT,
+      success: (res) => {
+        const statusCode = res.statusCode
+        if (statusCode >= 200 && statusCode < 300) {
+          const body = res.data as UTSJSONObject
+          const code = body.getNumber('code')
+          if (code != null && code == 200) {
+            resolve(body.get('data') as T)
+          } else {
+            const msg = body.getString('message') ?? '请求失败'
+            uni.showToast({ title: msg, icon: 'none' })
+            reject(new Error(msg))
+          }
+        } else {
+          const msg = '网络错误 ' + statusCode
+          uni.showToast({ title: msg, icon: 'none' })
+          reject(new Error(msg))
+        }
+      },
+      fail: (err) => {
+        const msg = err.errMsg ?? '请求失败'
+        uni.showToast({ title: msg, icon: 'none' })
+        reject(new Error(msg))
+      }
+    })
+  })
+}
+
+export function get<T>(url : string, data ?: UTSJSONObject | null) : Promise<T> {
+  return request<T>({ url: url, method: 'GET', data: data })
+}
+
+export function post<T>(url : string, data ?: UTSJSONObject | null) : Promise<T> {
+  return request<T>({ url: url, method: 'POST', data: data })
+}

+ 17 - 0
utils/storage.uts

@@ -0,0 +1,17 @@
+export type StorageKey = 'token' | 'userInfo'
+
+export function setStorage(key : StorageKey, value : any | null) {
+  uni.setStorageSync(key, value)
+}
+
+export function getStorage(key : StorageKey) : any | null {
+  return uni.getStorageSync(key)
+}
+
+export function removeStorage(key : StorageKey) {
+  uni.removeStorageSync(key)
+}
+
+export function clearStorage() {
+  uni.clearStorageSync()
+}