39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/src/stores/UpdateReplies.ts:
--------------------------------------------------------------------------------
1 | // This code is using the Pinia library to define a reactive store named UpdateReplies.
2 | // A store is a simple object that contains reactive state and methods to modify that state.
3 | // Stores are commonly used in Vue.js applications to manage global state.
4 |
5 | // The defineStore function from the Pinia library is used to create the UpdateReplies store.
6 | // It takes two arguments: the name of the store (a string), and an object containing the store's state and actions.
7 |
8 | // In this case, the state object contains a single property named update, which is initialized to 1.
9 | // The actions object contains a single method named Update.
10 | // This method takes a number parameter named status, and it increments the update property of the store's state by status.
11 |
12 | // Importing the defineStore function from the Pinia library
13 | import { defineStore } from "pinia";
14 |
15 | // Defining a store named UpdateReplies using the defineStore function
16 | export const UpdateReplies = defineStore(
17 | // The name of the store is 'UpdateReplies'
18 | "UpdateReplies",
19 | {
20 | // The state object contains reactive data for the store
21 | state: () => ({
22 | update: 1,
23 | }),
24 | // The actions object contains methods to modify the state
25 | actions: {
26 | // The Update action takes a number parameter named status
27 | Update(status: number) {
28 | // The update property of the state is incremented by status
29 | this.update = this.update + status;
30 | },
31 | // The ResetUpdate action resets the update property to 1
32 | ResetUpdate() {
33 | this.update = 1;
34 | },
35 | },
36 | }
37 | );
38 |
--------------------------------------------------------------------------------
/src/components/Admin/AdminPanel/Overview/Overview.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
概览
4 |
5 |
6 |
7 |
总用户数
8 |
{{ stats.userCount }}
9 |
10 |
11 |
总帖子数
12 |
{{ stats.postCount }}
13 |
14 |
15 |
总评论数
16 |
{{ stats.commentCount }}
17 |
18 |
19 |
今日新增用户
20 |
{{ stats.newUserToday }}
21 |
22 |
23 |
24 |
25 |
26 |
27 |
57 |
58 |
61 |
--------------------------------------------------------------------------------
/src/stores/UpdateImages.ts:
--------------------------------------------------------------------------------
1 | // stores/UpdateImages
2 | // This code defines a Pinia store named "UpdateImages"
3 | // which is used for managing image update status in a Vue.js application.
4 | // The defineStore function is imported from the Pinia library at the top of the file.
5 | // This function creates a new store instance based on a given name and configuration object.
6 | // The UpdateImages store is created using the defineStore function, with a unique name of "UpdateImage".
7 | // The configuration object passed to defineStore contains two properties: state and actions.
8 | // The state property is a function that returns an object containing the initial state of the store.
9 | // In this case, the only piece of state defined is update, which is initialized to 1.
10 | // This variable is used to keep track of the current update status of the images.
11 | // The actions property is an object that contains methods which can be called to modify the state of the store.
12 | // In this case, there is only one action defined, named Update.
13 | // This method takes a number argument named status and updates the update state variable by adding the status value to it.
14 | // This action can be used to update the image status within the store.
15 | // Overall, this code provides a simple implementation of a store for image update management in a Vue.js app.
16 |
17 | import { defineStore } from "pinia"; // Import the `defineStore` function from Pinia
18 |
19 | // Define a Pinia store named "UpdateImages"
20 | export const UpdateImages = defineStore("UpdateImage", {
21 | // Define the initial state of the store
22 | state: () => ({
23 | update: 1, // A number representing the current update status of the images
24 | }),
25 |
26 | // Define actions that can be used to modify the state of the store
27 | actions: {
28 | // This action takes a number value as its argument and updates the `update` state variable accordingly
29 | Update(status: number) {
30 | this.update = this.update + status;
31 | },
32 | ResetUpdate() {
33 | this.update = 1;
34 | },
35 | },
36 | });
37 |
--------------------------------------------------------------------------------
/src/components/Auth/LoginPanel.vue:
--------------------------------------------------------------------------------
1 |
2 |
40 |
41 |
42 |
93 |
94 |
97 |
--------------------------------------------------------------------------------
/src/stores/Authentication.ts:
--------------------------------------------------------------------------------
1 | // stores/Authentication.ts
2 | // This code defines a Pinia store named "Authentication"
3 | // which is used for managing authentication state in a Vue.js application.
4 | // At the top of the file, the defineStore function is imported from the Pinia library.
5 | // This function is used to create a new store instance based on a given name and configuration object.
6 | // The Authentication store is created using the defineStore function, with a unique name of "Authentication".
7 | // The configuration object passed to defineStore contains two properties: state and actions.
8 | // The state property is a function that returns an object containing the initial state of the store.
9 | // In this case, the only piece of state defined is isLogged, which is initialized to false.
10 | // This variable is used to keep track of whether the user is logged in or not.
11 | // The actions property is an object that contains methods which can be called to modify the state of the store.
12 | // In this case, there is only one action defined, named setLogStatus.
13 | // This method takes a boolean argument named status and sets the isLogged state variable to the value of status.
14 | // This action can be used to update the authentication status of the user within the store.
15 | // Overall, this code provides a simple implementation of a store for authentication management in a Vue.js app.
16 |
17 | import { defineStore } from "pinia"; // Import the `defineStore` function from Pinia library
18 | import axios from "axios"; // Import the `axios` library for making HTTP requests
19 |
20 | // Define a store named "Authentication" using the `defineStore` function
21 | export const useAuthenticationStore = defineStore("authentication", {
22 | // Define the initial state of the store
23 | state: () => ({
24 | isLogged: !!localStorage.getItem("auth_token"), // 根据localStorage中的token初始化登录状态
25 | token: localStorage.getItem("auth_token") || "", // A string to store the authentication token
26 | }),
27 |
28 | // Define actions that can be used to modify the state of the store
29 | actions: {
30 | // This action takes a boolean value as its argument and sets the `isLogged` state variable accordingly
31 | setLogStatus(status: boolean) {
32 | this.isLogged = status;
33 | },
34 | // This action takes a username and password, sends a login request, and updates the state accordingly
35 | async login(username: string, password: string) {
36 | try {
37 | const response = await axios.post('/user/token',
38 | new URLSearchParams({
39 | username,
40 | password
41 | }),
42 | {
43 | headers: {
44 | 'Content-Type': 'application/x-www-form-urlencoded'
45 | }
46 | }
47 | )
48 | this.token = response.data.access_token
49 | localStorage.setItem("auth_token", response.data.access_token)
50 | this.isLogged = true
51 | } catch (error: any) {
52 | this.token = ""
53 | localStorage.removeItem("auth_token")
54 | this.isLogged = false
55 | throw error // 确保错误被传递给调用者
56 | }
57 | },
58 | // This action logs the user out by clearing the token and updating the state
59 | logout() {
60 | this.token = "";
61 | localStorage.removeItem("auth_token");
62 | this.setLogStatus(false);
63 | },
64 | // This action checks the authentication status based on the token
65 | checkAuth() {
66 | if (this.token) {
67 | this.setLogStatus(true);
68 | } else {
69 | this.setLogStatus(false);
70 | }
71 | },
72 | },
73 | });
74 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # TinyGallery Vue Edition FrontEnd
2 |
3 | 
4 |
5 | Welcome to TinyGallery Vue Edition FrontEnd - an open-source project that provides a simple and free gallery service for drawing lovers. The project is divided into two parts: frontend and backend.
6 |
7 | The frontend is built using Vue.js, Vite, TypeScript, CSS3, and Yarn. It features a simple and clean user interface, fast and responsive design, and is easy to use and navigate.
8 |
9 | The backend is built using FastAPI, a modern, fast (high-performance), web framework for building APIs with Python 3.7+ based on standard Python type hints. The database used is SQLite, a lightweight disk-based database engine that doesn't require a separate server process. You can find the source code for the backend at [TinyGallery BackEnd](https://github.com/WeepingDogel/tinygallery-backend).
10 |
11 | ~~If you're interested in contributing to this project, please read our Contributing Guide for more information.~~
12 |
13 | # Features
14 |
15 | * Simple and clean user interface
16 | * Fast and responsive design
17 | * Easy to use and navigate
18 | * Free and open-source
19 |
20 |
21 | # Technology Stack
22 |
23 |
24 | ## Frontend
25 |
26 | The technology stack used in the frontend of this project includes:
27 |
28 | 
29 |
30 |
31 | * Vue.js: A popular JavaScript framework for building user interfaces.
32 | * Vite: An opinionated build tool that focuses on fast development and optimized builds.
33 | * TypeScript: A superset of JavaScript that adds optional static typing and other features to the language.
34 | * CSS3: The latest version of Cascading Style Sheets, which is used to style web pages.
35 | * Yarn: A package manager that allows for easy installation and management of dependencies.
36 |
37 |
38 | ## Backend
39 |
40 | The technology stack used in the backend of this project includes:
41 |
42 | 
43 |
44 | * FastAPI: A modern, fast (high-performance), web framework for building APIs with Python 3.7+ based on standard Python type hints.
45 | * SQLite: A lightweight disk-based database engine that doesn't require a separate server process.
46 |
47 | # Getting Started
48 |
49 | To get started with the TinyGallery Vue Edition FrontEnd, follow these steps:
50 |
51 | * Clone the repository:
52 | ```
53 | git clone https://github.com/WeepingDogel/tinygallery-vue.git
54 | ```
55 | * Enter the directory:
56 | ```
57 | cd tinygallery-vue
58 | ```
59 | * Install dependencies:
60 | ```
61 | yarn install
62 | ```
63 | * Start the development server:
64 | ```
65 | yarn dev
66 | ```
67 | * Open http://localhost:5173 in your browser
68 |
69 | # Contributing
70 |
71 | This project is open-source and contributions are welcome. If you want to contribute to the project, please read our Contributing Guide for more information.
72 |
73 | # License
74 |
75 | This project is licensed under the MIT License.
--------------------------------------------------------------------------------
/src/stores/TimeZone.ts:
--------------------------------------------------------------------------------
1 | // 1. The code imports the necessary dependencies:
2 | // defineStore from the Pinia library, axios for making HTTP requests,
3 | // and moment-timezone for working with timezones.
4 |
5 | // 2. The Timezone store is defined using defineStore.
6 | // It has two properties in its state:
7 | // TimeZoneServer and TimeZoneBrowser,
8 | // which will store the timezone of the server and the timezone of the browser, respectively.
9 |
10 | // 3. The GetTheTimeZoneOfServer action is responsible for retrieving the timezone of the server.
11 | // It makes an HTTP GET request to the /userdata/get/timezone endpoint using axios.
12 | // Upon a successful response,
13 | // the server's timezone is extracted from the response data and stored in the TimeZoneServer property.
14 | // The timezone is also logged to the console. If there's an error, the error details are returned.
15 |
16 | // 4. The GetTheLocalTimeZone action is responsible for retrieving the timezone of the browser.
17 | // It uses the Intl.DateTimeFormat().resolvedOptions().timeZone method to obtain the browser's timezone
18 | // and stores it in the TimeZoneBrowser property.
19 | // The timezone is also logged to the console.
20 |
21 | // 5. The CaculateTheCorrectDate action takes an original date as input
22 | // and calculates the correct date based on the original date,
23 | // server's timezone, and browser's timezone.
24 | // It first creates a moment object using the original date and the server's timezone (this.TimeZoneServer).
25 | // Then, it clones the moment object and converts it to the browser's timezone (this.TimeZoneBrowser).
26 | // Finally, it formats the date as "YYYY-MM-DD HH:mm" and returns the formatted date.
27 |
28 | // Overall, this code allows you to retrieve and manage the timezones of both the server and the browser,
29 | // and perform calculations to ensure that dates are displayed correctly based on the respective timezones.
30 |
31 | import { defineStore } from "pinia";
32 | import axios from "axios";
33 | import moment from "moment-timezone";
34 |
35 | export const Timezone = defineStore("TimeZone", {
36 | state: () => ({
37 | TimeZoneServer: "", // Stores the timezone of the server
38 | TimeZoneBrowser: "", // Stores the timezone of the browser
39 | }),
40 | actions: {
41 | // Retrieves the timezone of the server
42 | GetTheTimeZoneOfServer() {
43 | axios
44 | .get("/userdata/get/timezone")
45 | .then((response) => {
46 | // console.log(response);
47 | this.TimeZoneServer = response.data; // Sets the server's timezone based on the response data
48 | console.log(this.TimeZoneServer);
49 | })
50 | .catch((error) => {
51 | // console.log(error);
52 | return error.detail; // Returns the error details if there's an error
53 | });
54 | },
55 | // Retrieves the timezone of the browser
56 | GetTheLocalTimeZone() {
57 | const TimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone; // Gets the timezone of the browser
58 | this.TimeZoneBrowser = TimeZone; // Sets the browser's timezone
59 | console.log(this.TimeZoneBrowser);
60 | },
61 | // Manually sets the timezone of the server
62 | SetTimeZoneServer(timeZone: string) {
63 | this.TimeZoneServer = timeZone;
64 | },
65 | // Calculates the correct date based on the original date, server's timezone, and browser's timezone
66 | CaculateTheCorrectDate(OriginalDate: String) {
67 | const dateString = OriginalDate;
68 | return moment
69 | .tz(dateString, this.TimeZoneServer) // Converts the original date to the server's timezone
70 | .clone()
71 | .tz(this.TimeZoneBrowser) // Converts the date to the browser's timezone
72 | .format("YYYY-MM-DD HH:mm"); // Formats the date as "YYYY-MM-DD HH:mm"
73 | },
74 | },
75 | });
76 |
--------------------------------------------------------------------------------
/src/components/Profile/Profile.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
19 |
{{ profileData.username }}
20 |
21 |
22 |
23 |
24 | 编辑资料
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
98 |
99 |
113 |
--------------------------------------------------------------------------------
/src/router/index.ts:
--------------------------------------------------------------------------------
1 | // import { createRouter, createWebHistory } from 'vue-router':
2 | // This imports the createRouter() and createWebHistory() functions from the Vue Router library.
3 |
4 | // import HomePage from '../views/HomeView.vue':
5 | // This imports the HomeView.vue file from the views folder.
6 |
7 | // const router = createRouter({ ... }):
8 | // This creates the router object with the specified configuration.
9 | // It takes an object with two properties: history and routes.
10 |
11 | // history: createWebHistory(import.meta.env.BASE_URL),:
12 | // This sets the history mode to "web history" and uses the BASE_URL environment variable to set the base URL of the app.
13 |
14 | // routes: [ ... ]:
15 | // This defines an array of route objects which map a URL path to a specific component.
16 |
17 | // { path: '/', name: 'home', component: HomePage }:
18 | // This sets the root path to the HomePage component and names it 'home'.
19 |
20 | // { path: '/login', name: 'login', component: () => import('../views/AuthView.vue') }:
21 | // This sets the /login path to the AuthView component and names it 'login'.
22 | // The component is loaded lazily using the import() function.
23 |
24 | // { path: '/about', name: 'about', component: () => import('../views/AboutView.vue') }:
25 | // This sets the /about path to the AboutView component and names it 'about'.
26 | // The component is loaded lazily using the import() function.
27 |
28 | // { path: '/profile', name: 'Profile', component: () => import('../views/ProfileView.vue') }:
29 | // This sets the /profile path to the ProfileView component and names it 'Profile'.
30 | // The component is loaded lazily using the import() function.
31 |
32 | // { path: '/remark/:post_uuid', name: 'Remark', component: () => import('../views/RemarkView.vue') }:
33 | // This sets the /remark path with a dynamic parameter named post_uuid to the RemarkView component and names it 'Remark'.
34 | // The component is loaded lazily using the import() function.
35 |
36 | // export default router: This exports the router object as the default export.
37 |
38 | // Import the necessary functions from vue-router
39 | import { createRouter, createWebHistory } from "vue-router";
40 | // Import the different views for each page
41 | import HomePage from "../views/HomeView.vue";
42 |
43 | // Define the router object
44 | const router = createRouter({
45 | // Use web history API to maintain browser history
46 | history: createWebHistory(import.meta.env.BASE_URL),
47 | routes: [
48 | {
49 | // Define the home page route
50 | path: "/",
51 | name: "home",
52 | component: HomePage,
53 | },
54 | {
55 | // Define the login page route
56 | path: "/login",
57 | name: "login",
58 | component: () => import("../views/AuthView.vue"),
59 | },
60 | {
61 | // Define the about page route
62 | path: "/about",
63 | name: "about",
64 | component: () => import("../views/AboutView.vue"),
65 | },
66 | {
67 | // Define the profile page route
68 | path: "/profile",
69 | name: "Profile",
70 | component: () => import("../views/ProfileView.vue"),
71 | },
72 | {
73 | // Define the edit profile page route
74 | path: "/profile/edit",
75 | name: "EditProfile",
76 | component: () => import("../views/EditProfileView.vue"),
77 | },
78 | {
79 | // Define the remark page route with a dynamic parameter
80 | path: "/remark/:uuid",
81 | name: "Remark",
82 | component: () => import("../views/RemarkView.vue"),
83 | },
84 | {
85 | path: "/admin",
86 | name: "Administration",
87 | component: () => import("../views/AdminView.vue"),
88 | },
89 | {
90 | path: "/register",
91 | name: "register",
92 | component: () => import("../views/RegisterView.vue"),
93 | }
94 | ],
95 | });
96 |
97 | export default router;
98 |
--------------------------------------------------------------------------------
/src/components/Profile/PostsList.vue:
--------------------------------------------------------------------------------
1 |
2 |