Browse Source

vue代码 src

Administrator 1 year ago
parent
commit
403e0f934b

+ 20 - 0
frontend/src/App.vue

@@ -0,0 +1,20 @@
+<template>
+  <router-view/>
+</template>
+<script lang="ts" setup>
+
+import {ref} from "vue";
+import LoginPage from "./pages/LoginPage.vue";
+import MainPage from "./pages/MainPage.vue";
+
+let isLogin = ref<boolean>(false)
+let filePath = ref<string>("");
+
+// OnFileDrop((x, y, paths) => {
+//   console.log(x, y, "前端路径4:", paths)
+//   filePath.value = paths[0]
+// }, false)
+
+</script>
+<style lang="scss" scoped>
+</style>

+ 133 - 0
frontend/src/components/UploadFilePath.vue

@@ -0,0 +1,133 @@
+<template>
+  <div class="drag-upload-container">
+    <el-upload
+        action="#"
+        drag
+        :auto-upload="false"
+        :on-change="handleFileChange"
+        :show-file-list="false">
+      <div class="drag-area" :class="{ 'dragover': isDragging }">
+        <el-icon :size="40" :color="'#ff0000'">
+          <upload-filled/>
+        </el-icon>
+        <el-text class="upload-text">
+          将文件拖到此处,或<el-link :type="'primary'" @click="">点击选择</el-link>
+        </el-text>
+        <div class="el-upload__tip">
+          支持单个文件上传(暂不限制文件类型)
+        </div>
+      </div>
+    </el-upload>
+
+    <!-- 文件信息展示 -->
+<!--    <div v-if="fileInfo" class="file-info">-->
+<!--      <el-icon class="file-icon">-->
+<!--        <document/>-->
+<!--      </el-icon>-->
+<!--      <div class="file-details">-->
+<!--        <div class="file-name">{{ fileInfo.name }}</div>-->
+<!--        <div class="file-size">{{ formatFileSize(fileInfo.size) }}</div>-->
+<!--        <div class="file-path">临时路径:{{ tempPath }}</div>-->
+<!--      </div>-->
+<!--    </div>-->
+  </div>
+</template>
+
+<script setup lang="ts">
+import {ref} from 'vue'
+import {Document, UploadFilled} from '@element-plus/icons-vue'
+
+interface UploadFile {
+  name: string
+  size: number
+  raw: File
+}
+
+const isDragging = ref(false)
+const tempPath = ref('')
+const fileInfo = ref<UploadFile | null>(null)
+
+const handleFileChange = (uploadFile: any) => {
+  console.log('handleFileChange'+uploadFile)
+  const file = uploadFile.raw
+  if (file) {
+    fileInfo.value = {
+      name: file.name,
+      size: file.size,
+      raw: file
+    }
+    // 生成临时路径(实际使用中根据需求处理)
+    tempPath.value = URL.createObjectURL(file)
+  }
+}
+
+const formatFileSize = (bytes: number) => {
+  if (bytes === 0) return '0 B'
+  const k = 1024
+  const sizes = ['B', 'KB', 'MB', 'GB']
+  const i = Math.floor(Math.log(bytes) / Math.log(k))
+  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
+}
+</script>
+
+<style scoped>
+.drag-upload-container {
+  max-width: 600px;
+  margin: 20px auto;
+  padding: 20px;
+}
+
+.drag-area {
+  padding: 40px 20px;
+  border: 2px dashed #dcdfe6;
+  border-radius: 6px;
+  transition: border-color 0.3s;
+}
+
+.el-icon--upload {
+  color: #8c939d;
+  margin-bottom: 16px;
+}
+
+
+.el-upload__tip {
+  color: #909399;
+  font-size: 12px;
+}
+
+.file-info {
+  margin-top: 20px;
+  padding: 15px;
+  background-color: #f5f7fa;
+  border-radius: 4px;
+  display: flex;
+  align-items: center;
+}
+
+.file-icon {
+  font-size: 40px;
+  color: #909399;
+  margin-right: 15px;
+}
+
+.file-details {
+  flex: 1;
+}
+
+.file-name {
+  font-weight: 500;
+  color: #303133;
+}
+
+.file-size {
+  font-size: 12px;
+  color: #909399;
+  margin: 4px 0;
+}
+
+.file-path {
+  font-size: 12px;
+  color: #606266;
+  word-break: break-all;
+}
+</style>

+ 14 - 0
frontend/src/main.ts

@@ -0,0 +1,14 @@
+import {createApp} from 'vue'
+import  './style.css'
+import 'element-plus/dist/index.css'
+import App from './App.vue'
+
+import router from './router'
+import axios from 'axios'
+import ElementPlus from 'element-plus'
+
+createApp(App)
+    .use(router)
+    .use(ElementPlus)
+    .provide('$axios', axios)
+    .mount('#app')

+ 224 - 0
frontend/src/modules/LoginBar.vue

@@ -0,0 +1,224 @@
+<template>
+  <div class="login-container" style="--wails-draggable:drag">
+    <div class="login-box">
+      <h2 class="title">用户登录</h2>
+
+      <form @submit.prevent="handleSubmit">
+        <div class="form-group">
+          <label for="username">用户名</label>
+          <input
+              v-model="formData.username"
+              type="text"
+              id="username"
+              required
+              :disabled="isLoading"
+          />
+        </div>
+
+        <div class="form-group">
+          <label for="password">密码</label>
+          <input
+              v-model="formData.password"
+              type="password"
+              id="password"
+              required
+              :disabled="isLoading"
+          />
+        </div>
+
+        <div class="remember-me">
+          <input
+              type="checkbox"
+              id="remember"
+              v-model="formData.rememberMe"
+          />
+          <label for="remember">记住我</label>
+        </div>
+
+        <button
+            type="submit"
+            class="submit-btn"
+            :disabled="isLoading"
+        >
+          {{ isLoading ? '登录中...' : '立即登录' }}
+        </button>
+
+        <div v-if="errorMessage" class="error-message">
+          {{ errorMessage }}
+        </div>
+      </form>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, reactive } from 'vue'
+import axios from 'axios'
+import type { AxiosError } from 'axios'
+
+interface LoginForm {
+  username: string
+  password: string
+  rememberMe: boolean
+}
+
+interface LoginResponse {
+  token: string
+  userInfo: {
+    id: number
+    username: string
+  }
+}
+
+
+// 表单数据
+const formData = reactive<LoginForm>({
+  username: '',
+  password: '',
+  rememberMe: false
+})
+
+// 状态管理
+const isLoading = ref(false)
+const errorMessage = ref('')
+
+// 创建 axios 实例
+const api = axios.create({
+  baseURL: import.meta.env.VITE_API_BASE_URL,
+  timeout: 5000
+})
+
+const handleSubmit = async () => {
+  if (!formData.username || !formData.password) {
+    errorMessage.value = '请输入用户名和密码'
+    return
+  }
+
+  try {
+    isLoading.value = true
+    errorMessage.value = ''
+
+    const response = await api.post<LoginResponse>('/login', {
+      username: formData.username,
+      password: formData.password
+    })
+
+    // 处理登录成功
+    handleLoginSuccess(response.data)
+  } catch (error) {
+    handleLoginError(error as AxiosError)
+  } finally {
+    isLoading.value = false
+  }
+}
+
+const handleLoginSuccess = (data: LoginResponse) => {
+  // 存储 token
+  localStorage.setItem('token', data.token)
+
+  // 如果选择记住我,存储用户名
+  if (formData.rememberMe) {
+    localStorage.setItem('username', formData.username)
+  } else {
+    localStorage.removeItem('username')
+  }
+
+}
+
+const handleLoginError = (error: AxiosError) => {
+  if (error.response) {
+    switch (error.response.status) {
+      case 401:
+        errorMessage.value = '用户名或密码错误'
+        break
+      case 500:
+        errorMessage.value = '服务器错误,请稍后再试'
+        break
+      default:
+        errorMessage.value = '登录失败,请重试'
+    }
+  } else {
+    errorMessage.value = '网络连接异常,请检查网络'
+  }
+}
+</script>
+
+<style scoped>
+.login-container {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  min-height: 100vh;
+  background: #f0f2f5;
+}
+
+.login-box {
+  background: white;
+  padding: 2rem;
+  border-radius: 8px;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+  width: 400px;
+}
+
+.title {
+  text-align: center;
+  color: #333;
+  margin-bottom: 1.5rem;
+}
+
+.form-group {
+  margin-bottom: 1rem;
+}
+
+label {
+  display: block;
+  margin-bottom: 0.5rem;
+  color: #666;
+}
+
+input[type="text"],
+input[type="password"] {
+  width: 100%;
+  padding: 0.8rem;
+  border: 1px solid #ddd;
+  border-radius: 4px;
+  font-size: 1rem;
+}
+
+.remember-me {
+  margin: 1rem 0;
+  display: flex;
+  align-items: center;
+}
+
+.remember-me input {
+  margin-right: 0.5rem;
+}
+
+.submit-btn {
+  width: 100%;
+  padding: 0.8rem;
+  background: #1890ff;
+  color: white;
+  border: none;
+  border-radius: 4px;
+  cursor: pointer;
+  font-size: 1rem;
+  transition: background 0.3s;
+}
+
+.submit-btn:hover {
+  background: #40a9ff;
+}
+
+.submit-btn:disabled {
+  background: #8fc7ff;
+  cursor: not-allowed;
+}
+
+.error-message {
+  color: #ff4d4f;
+  margin-top: 1rem;
+  text-align: center;
+}
+</style>

+ 97 - 0
frontend/src/modules/StatusBar.vue

@@ -0,0 +1,97 @@
+<!--app 状态栏-->
+<template>
+  <div id="status-bar" style="--wails-draggable:drag">
+    <div id="status-bar-logo">
+      <img src="../assets/images/status-bar-logo.jpg" alt="logo"/>
+    </div>
+    <div id="status-bar-title" style="--wails-draggable:drag">
+      <el-text type="info" style="--wails-draggable:drag">标题</el-text>
+    </div>
+    <div id="status-bar-control-buttons">
+      <div class="status-bar-control-button">
+        <el-icon>
+          <Minus/>
+        </el-icon>
+      </div>
+      <div class="status-bar-control-button" @click="Window.ToggleMaximise()">
+        <el-icon>
+          <FullScreen/>
+        </el-icon>
+      </div>
+      <div class="status-bar-control-button" @click="Application.Quit()">
+        <el-icon>
+          <Close/>
+        </el-icon>
+      </div>
+    </div>
+  </div>
+</template>
+<script setup lang="ts">
+
+import {Close, FullScreen, Minus} from "@element-plus/icons-vue";
+import {Application, Window} from '@wailsio/runtime';
+
+</script>
+<style scoped lang="scss">
+#status-bar {
+  height: 32px;
+  background-color: rgba(255, 255, 255, 1);
+  display: flex;
+  flex-direction: row;
+  justify-content: space-between;
+  box-shadow: 0 3px 2px rgba(0, 0, 0, 0.05);
+
+  #status-bar-logo {
+    margin-left: 3px;
+
+    img {
+      width: 28px;
+      height: 28px;
+      margin-top: 2px;
+      border-radius: 5px;
+      user-select: none;
+    }
+  }
+
+  #status-bar-title {
+    line-height: 32px;
+    font-size: 17px;
+    user-select: none;
+  }
+
+  #status-bar-control-buttons {
+    display: flex;
+    flex-direction: row;
+    line-height: 32px;
+
+    .status-bar-control-button {
+      line-height: 38px;
+      width: 30px;
+      border: 1px solid #e2e4ec;
+      border-radius: 5px;
+      margin-left: 2px;
+      cursor: pointer;
+      transition: color 0.2s, background-color 0.2s;
+
+      &:hover {
+        background-color: #e2e4ec;
+      }
+
+      &:active {
+        background-color: #d5d9e1;
+      }
+
+      &:last-child:hover {
+        background-color: #e81123;
+        color: white;
+      }
+
+      &:last-child:active {
+        background-color: #f1707a;
+        color: white;
+      }
+    }
+  }
+}
+
+</style>

+ 20 - 0
frontend/src/pages/LoginPage.vue

@@ -0,0 +1,20 @@
+<!--登录页面-->
+<template>
+  <div id="login-page" style="--wails-draggable:drag" >
+    <div class="login-container">
+      <router-link to="/">主页面</router-link>
+    </div>
+  </div>
+</template>
+<script setup lang="ts">
+//判断是否登录
+
+
+</script>
+<style scoped lang="scss">
+.login-container{
+  width: 100VW;
+  height: 100VH;
+  background-image: url("../assets/images/background.jpg");
+}
+</style>

+ 28 - 0
frontend/src/pages/MainPage.vue

@@ -0,0 +1,28 @@
+<!--主页面-->
+<template>
+  <!--  <status-bar/>-->
+  <div id="main-page">
+    <status-bar/>
+    <UploadFilePath/>
+    {{msg}}+{{router.currentRoute.value.path}}
+    <br>
+    <router-link to="/login">登录页面</router-link>
+    <el-button @click="OpenLoginPage()">打开新窗口</el-button>
+  </div>
+</template>
+<script setup lang="ts">
+import StatusBar from "../modules/StatusBar.vue";
+import UploadFilePath from "../components/UploadFilePath.vue";
+import {ref} from "vue";
+import {OpenLoginPage} from "../../bindings/file-manage-ui/handler/service";
+import router from "../router";
+
+let msg = ref("Hello World");
+
+</script>
+<style scoped lang="scss">
+#main-page {
+  width: 100VW;
+  background-color: #8c939d;
+}
+</style>

+ 25 - 0
frontend/src/router/index.ts

@@ -0,0 +1,25 @@
+import {createRouter, createWebHashHistory, RouteRecordRaw} from "vue-router";
+// 2. 配置路由
+const routes: Array<RouteRecordRaw> = [
+    {
+        name: "home",
+        path: "/",
+        component: () => import("../pages/MainPage.vue"),
+        children: []
+    },
+    {
+        name: "main",
+        path: "/login",
+        component: () => import("../pages/LoginPage.vue"),
+        children: []
+    }
+];
+
+// 1.返回一个 router 实列,为函数,里面有配置项(对象) history
+const router = createRouter({
+    history: createWebHashHistory(),
+    routes,
+});
+
+// 3导出路由   然后去 main.ts 注册 router.ts
+export default router

+ 29 - 0
frontend/src/style.css

@@ -0,0 +1,29 @@
+html {
+    /*background-color: rgba(27, 38, 54, 1);*/
+    text-align: center;
+}
+
+body {
+    margin: 0;
+    font-family: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
+    "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
+    sans-serif;
+    place-items: start;
+    display: block;
+}
+
+@font-face {
+    font-family: "Nunito";
+    font-style: normal;
+    font-weight: 400;
+    src: local(""),
+    url("assets/fonts/nunito-v16-latin-regular.woff2") format("woff2");
+}
+
+#app{
+    margin: 0;
+    padding: 0;
+    display: block;
+    width: 100VW;
+    height: 100VH;
+}

+ 1 - 0
frontend/src/vite-env.d.ts

@@ -0,0 +1 @@
+/// <reference types="vite/client" />