rebuild: store

This commit is contained in:
KUN1007 2023-09-28 21:07:12 +08:00
parent 9103344bea
commit 9085d74750
16 changed files with 289 additions and 325 deletions

View file

@ -42,6 +42,8 @@ const handelInput = () => {
//
if (topicTitle.value.trim() === '') {
title.value = ''
topicRewrite.value.title = ''
return
}
@ -52,7 +54,6 @@ const handelInput = () => {
*/
// edit store
if (!topicRewrite.value.isTopicRewriting) {
// xss
title.value = topicTitle.value
}
/**

View file

@ -1,26 +1,52 @@
/**
* KUNGalgame pinia pinia-plugin-persistedstate
*
*/
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
import type { App } from 'vue'
// 导入编辑界面 store
import { useKUNGalgameEditStore } from './modules/edit'
// 导入 home store
import { useKUNGalgameHomeStore } from './modules/home'
// 导入用户 store
import { useKUNGalgameUserStore } from '@/store/modules/kungalgamer'
// 导入 message store
import { useKUNGalgameMessageStore } from './modules/message'
// 导入网站设置面板 store
import { useKUNGalgameSettingsStore } from '@/store/modules/settings'
// 导入话题详情页面的 store
import { useKUNGalgameTopicStore } from './modules/topic'
const store = createPinia()
// 设置 pinia 的函数,在 main.ts 挂载
export function setupPinia(app: App<Element>) {
store.use(piniaPluginPersistedstate)
app.use(store)
}
// 重置所有 store用于登出
export function storeReset() {
const editStore = useKUNGalgameEditStore()
const homeStore = useKUNGalgameHomeStore()
const userStore = useKUNGalgameUserStore()
const messageStore = useKUNGalgameMessageStore()
const settingsStore = useKUNGalgameSettingsStore()
const topicStore = useKUNGalgameTopicStore()
editStore.$reset()
homeStore.$reset()
userStore.$reset()
messageStore.$reset()
settingsStore.$reset()
topicStore.$reset()
}
export { store }

View file

@ -16,14 +16,14 @@ import {
EditGetHotTagsResponseData,
} from '@/api'
// store interface
import { Topic } from '../types/edit'
import { EditStore } from '../types/edit'
// some utils to check topic publish data is valid
import { checkTopicPublish } from '../utils/checkTopicPublish'
export const useKUNGalgameEditStore = defineStore({
id: 'edit',
persist: true,
state: (): Topic => ({
state: (): EditStore => ({
editorHeight: 300,
textCount: 0,
mode: '',
@ -49,7 +49,7 @@ export const useKUNGalgameEditStore = defineStore({
getters: {},
actions: {
// 创建话题
createNewTopic(): Promise<EditCreateTopicResponseData> | undefined {
async createNewTopic(): Promise<EditCreateTopicResponseData | undefined> {
// 当前话题的数据
const requestData: EditCreateTopicRequestData = {
title: this.title,
@ -63,18 +63,10 @@ export const useKUNGalgameEditStore = defineStore({
return
}
// 合法则请求接口发布话题
return new Promise((resolve, reject) => {
postEditNewTopicApi(requestData)
.then((res) => {
resolve(res)
})
.catch((error) => {
reject(error)
})
})
return await postEditNewTopicApi(requestData)
},
// 更新话题
async rewriteTopic(): Promise<EditUpdateTopicResponseData> {
async rewriteTopic(): Promise<EditUpdateTopicResponseData | undefined> {
const requestData: EditUpdateTopicRequestData = {
tid: this.topicRewrite.tid,
title: this.topicRewrite.title,
@ -82,20 +74,16 @@ export const useKUNGalgameEditStore = defineStore({
tags: this.topicRewrite.tags,
category: this.topicRewrite.category,
}
// 检查话题数据不合法直接返回
if (!checkTopicPublish(this.textCount, requestData)) {
return
}
return await updateEditNewTopicApi(requestData)
},
// 获取热门 tags
getHotTags(limit: number): Promise<EditGetHotTagsResponseData> {
return new Promise((resolve, reject) => {
const requestData: EditGetHotTagsRequestData = { limit }
getTopTagsApi(requestData)
.then((res) => {
resolve(res)
})
.catch((error) => {
reject(error)
})
})
async getHotTags(limit: number): Promise<EditGetHotTagsResponseData> {
const requestData: EditGetHotTagsRequestData = { limit }
return await getTopTagsApi(requestData)
},
// 重置话题草稿数据,用于发布时
resetTopicData() {
@ -109,6 +97,7 @@ export const useKUNGalgameEditStore = defineStore({
},
// 重置重新发布话题数据,用于重新编辑
resetRewriteTopicData() {
this.textCount = 0
this.topicRewrite.title = ''
this.topicRewrite.content = ''
this.topicRewrite.tags = []

View file

@ -1,27 +1,12 @@
/* 主页的 store */
import { defineStore } from 'pinia'
// api
import { getHomeTopicApi } from '@/api/index'
// 数据接口的类型
import { HomeTopicRequestData, HomeTopicResponseData } from '@/api/index'
interface HomeStore {
keywords: string
category: string
page: number
limit: number
sortField: string
sortOrder: string
// 加载完了是否还需要加载
isLoading: boolean
// 其它的 store
// 是否激活主页的左侧交互面板
isActiveMainPageAside: boolean
// 搜索历史存储
searchHistory: string[]
}
// home store 的类型
import { HomeStore } from '../types/home'
export const useKUNGalgameHomeStore = defineStore({
id: 'home',
@ -55,7 +40,7 @@ export const useKUNGalgameHomeStore = defineStore({
getters: {},
actions: {
// 获取首页话题
getHomeTopic(): Promise<HomeTopicResponseData> {
async getHomeTopic(): Promise<HomeTopicResponseData> {
// 这里的值用于初始化
const requestData: HomeTopicRequestData = {
keywords: this.keywords,
@ -65,15 +50,7 @@ export const useKUNGalgameHomeStore = defineStore({
sortField: this.sortField,
sortOrder: this.sortOrder,
}
return new Promise((resolve, reject) => {
getHomeTopicApi(requestData)
.then((res) => {
resolve(res)
})
.catch((error) => {
reject(error)
})
})
return await getHomeTopicApi(requestData)
},
// 重置页数,是否加载,这样排序才能生效
resetPageStatus() {

View file

@ -14,19 +14,14 @@ import {
sendVerificationCodeMailApi,
} from '@/api'
// 用户信息接口
interface UserState {
uid: number
name: string
avatar: string
moemoeAccessToken: string
}
// kungalgame store 类型
import { KUNGalgamerStore } from '../types/kungalgamer'
// 这里用了 pinia-plugin-persistedstate直接存储即可
export const useKUNGalgameUserStore = defineStore({
id: 'kungalgamer',
persist: true,
state: (): UserState => ({
state: (): KUNGalgamerStore => ({
uid: 0,
name: '',
avatar: '',
@ -50,56 +45,36 @@ export const useKUNGalgameUserStore = defineStore({
this.moemoeAccessToken = ''
},
// 登陆
login(request: LoginRequestData): Promise<LoginResponseData> {
return new Promise((resolve, reject) => {
// 这里是向后端发请求的函数
postLoginDataApi(request)
.then((res) => {
if (res.data) {
this.setUserInfo(res.data.uid, res.data.name, res.data.avatar)
this.setToken(res.data.token)
} else
(error: Error) => {
throw new Error('500 Server ERROR', error)
}
resolve(res)
})
.catch((error) => {
reject(error)
})
})
async login(request: LoginRequestData): Promise<LoginResponseData> {
const res = await postLoginDataApi(request)
if (res.code === 200) {
this.setUserInfo(res.data.uid, res.data.name, res.data.avatar)
this.setToken(res.data.token)
} else if (res.code === 500) {
console.log(res.message)
} else {
throw new Error('500 Server ERROR')
}
return res
},
// 发送验证码
sendCode(email: string): Promise<void> {
return new Promise((resolve, reject) => {
const request: VerificationCodeMailRequestData = { email }
sendVerificationCodeMailApi(request)
.then((res) => {
resolve(res)
})
.catch((error) => {
reject(error)
})
})
async sendCode(email: string): Promise<void> {
const request: VerificationCodeMailRequestData = { email }
return await sendVerificationCodeMailApi(request)
},
// 注册
register(request: RegisterRequestData): Promise<LoginResponseData> {
return new Promise((resolve, reject) => {
postRegisterDataApi(request)
.then((res) => {
if (res.data) {
this.setUserInfo(res.data.uid, res.data.name, res.data.avatar)
this.setToken(res.data.token)
} else
(error: Error) => {
throw new Error('500 Server ERROR', error)
}
resolve(res)
})
.catch((error) => {
reject(error)
})
})
async register(request: RegisterRequestData): Promise<LoginResponseData> {
const res = await postRegisterDataApi(request)
if (res.code === 200) {
this.setUserInfo(res.data.uid, res.data.name, res.data.avatar)
this.setToken(res.data.token)
} else if (res.code === 500) {
console.log(res.message)
} else {
throw new Error('500 Server ERROR')
}
return res
},
},
})

View file

@ -1,31 +1,13 @@
import { defineStore } from 'pinia'
interface Message {
// 是否展示通知消息
showInfo: boolean
// 是否展示警告消息
showAlert: boolean
// 通知消息的内容
infoMsg: string
// 警告消息的内容
alertMsg: string
// 是否展示取消按钮Alert 组件专用
isShowCancel: boolean
// 返回确认信息Alert 组件专用
confirm: boolean
// 人机验证组件
// 是否显示人机验证
isShowCapture: boolean
// 是否验证通过
isCaptureSuccessful: boolean
}
// message store 的类型
import { MessageStore } from '../types/message'
export const useKUNGalgameMessageStore = defineStore({
id: 'message',
// 所有消息组件均不需要持久存储
persist: false,
state: (): Message => ({
state: (): MessageStore => ({
showInfo: false,
showAlert: false,
infoMsg: '',

View file

@ -4,30 +4,14 @@ import { defineStore } from 'pinia'
// 网站的默认设置
import { KUNGalgameLanguage, mode } from '@/utils/getDefaultEnv'
// 设置面板配置
interface KUNGalgameSettings {
// 白天黑夜模式切换
showKUNGalgameMode: string
// 网站显示语言
showKUNGalgameLanguage: string
// 主页宽度
showKUNGalgamePageWidth: Record<string, number>
// 网站字体
showKUNGalgameFontStyle: string
// 背景图
showKUNGalgameBackground: string
// 自定义背景图
showKUNGalgameCustomBackground: string
// 显示页面宽度还是显示字体设置
isShowPageWidth: boolean
}
// settings store 的类型
import { KUNGalgameSettingsStore } from '../types/settings'
export const useKUNGalgameSettingsStore = defineStore({
id: 'KUNGalgame-settings',
persist: true,
// 默认值
state: (): KUNGalgameSettings => ({
state: (): KUNGalgameSettingsStore => ({
showKUNGalgameMode: mode,
showKUNGalgameLanguage: KUNGalgameLanguage,
showKUNGalgamePageWidth: {

View file

@ -28,91 +28,13 @@ import {
TopicCreateCommentResponseData,
} from '@/api'
// 回复的缓存
interface ReplyDraft {
/**
*
* @param {number} editorHeight -
* @param {'' | 'essential' | 'minimal' | 'full'} mode - toolbar
* @param {'snow' | 'bubble'} theme -
*/
editorHeight: number
textCount: number
// 这里仅支持三种模式
mode: '' | 'essential' | 'minimal'
theme: 'snow' | 'bubble'
// 是否显示热门关键词
isShowHotKeywords: boolean
// 当前话题的 id
tid: number
r_uid: number
// 回复给谁,用于回复面板展示
replyUserName: string
to_uid: number
content: string
tags: string[]
// 被回复的人的楼层数,用于跳转
to_floor: number
// 是否保存回复
isSaveReply: boolean
// 回复发布的状态,如果状态有变化则将发布好的回复数据添加在回复数组里
// 这里与 true 和 false 无关,关心的是它的状态改变
publishStatus: boolean
}
// 获取回复的请求
interface ReplyRequest {
page: number
limit: number
sortField: string
sortOrder: 'asc' | 'desc'
}
// 评论的缓存
interface CommentDraft {
// 评论的内容
tid: number
rid: number
c_uid: number
to_uid: number
content: string
// 显示哪个评论的评论面板
isShowCommentPanelRid: number
}
// 话题页面的 store
interface Topic {
// 是否正在被编辑
isEdit: boolean
// 是否显示高级编辑模式
isShowAdvance: boolean
// 是否激活左侧交互面板
isActiveAside: boolean
// 是否滚动到顶部
isScrollToTop: boolean
// 加载完了是否还需要加载
isLoading: boolean
// 要滚动到的回复 id
scrollToReplyId: number
// 回复面板的宽度
replyPanelWidth: number
// 回复的缓存
replyDraft: ReplyDraft
// 获取回复的请求接口格式
replyRequest: ReplyRequest
// 评论的缓存
commentDraft: CommentDraft
}
// 导入 topic store 的类型
import { TopicStore } from '../types/topic'
export const useKUNGalgameTopicStore = defineStore({
id: 'topic',
persist: true,
state: (): Topic => ({
state: (): TopicStore => ({
isEdit: false,
isShowAdvance: false,
isActiveAside: false,
@ -158,115 +80,66 @@ export const useKUNGalgameTopicStore = defineStore({
}),
actions: {
// 左侧相同标签下的其它话题
getRelatedTopicsByTags(
async getRelatedTopicsByTags(
request: TopicAsideOtherTagRequestData
): Promise<TopicAsideResponseData> {
return new Promise((resolve, reject) => {
getRelatedTopicsByTagsApi(request)
.then((res) => {
resolve(res)
})
.catch((error) => {
reject(error)
})
})
return await getRelatedTopicsByTagsApi(request)
},
// 楼主的其它话题
getPopularTopicsByUserUid(
async getPopularTopicsByUserUid(
request: TopicAsideMasterRequestData
): Promise<TopicAsideResponseData> {
return new Promise((resolve, reject) => {
getPopularTopicsByUserUidApi(request)
.then((res) => {
resolve(res)
})
.catch((error) => {
reject(error)
})
})
return await getPopularTopicsByUserUidApi(request)
},
// 获取单个话题
getTopicByTid(tid: number): Promise<TopicDetailResponseData> {
return new Promise((resolve, reject) => {
getTopicByTidApi(tid)
.then((res) => {
resolve(res)
})
.catch((error) => {
reject(error)
})
})
async getTopicByTid(tid: number): Promise<TopicDetailResponseData> {
return await getTopicByTidApi(tid)
},
// 获取回复
getReplies(tid: number): Promise<TopicReplyResponseData> {
return new Promise((resolve, reject) => {
// 这里的默认值用于初始化
const requestData: TopicReplyRequestData = {
tid: tid,
page: this.replyRequest.page,
limit: this.replyRequest.limit,
sortField: this.replyRequest.sortField || 'floor',
sortOrder: this.replyRequest.sortOrder || 'desc',
}
getRepliesByPidApi(requestData)
.then((res) => {
resolve(res)
})
.catch((error) => {
reject(error)
})
})
async getReplies(tid: number): Promise<TopicReplyResponseData> {
// 这里的默认值用于初始化
const requestData: TopicReplyRequestData = {
tid: tid,
page: this.replyRequest.page,
limit: this.replyRequest.limit,
sortField: this.replyRequest.sortField || 'floor',
sortOrder: this.replyRequest.sortOrder || 'desc',
}
return await getRepliesByPidApi(requestData)
},
// 创建回复
postNewReply(): Promise<TopicCreateReplyResponseData> {
return new Promise((resolve, reject) => {
// 这里的值用于初始化回复
const requestData: TopicCreateReplyRequestData = {
tid: this.replyDraft.tid,
to_uid: this.replyDraft.to_uid,
to_floor: this.replyDraft.to_floor,
tags: this.replyDraft.tags,
content: this.replyDraft.content,
}
postReplyByPidApi(requestData)
.then((res) => {
resolve(res)
})
.catch((error) => {
reject(error)
})
})
async postNewReply(): Promise<TopicCreateReplyResponseData> {
// 这里的值用于初始化回复
const requestData: TopicCreateReplyRequestData = {
tid: this.replyDraft.tid,
to_uid: this.replyDraft.to_uid,
to_floor: this.replyDraft.to_floor,
tags: this.replyDraft.tags,
content: this.replyDraft.content,
}
return await postReplyByPidApi(requestData)
},
// 获取评论
getComments(rid: number): Promise<TopicCommentResponseData> {
return new Promise((resolve, reject) => {
getCommentsByReplyRidApi(rid)
.then((res) => {
resolve(res)
})
.catch((error) => {
reject(error)
})
})
async getComments(rid: number): Promise<TopicCommentResponseData> {
return await getCommentsByReplyRidApi(rid)
},
// 创建一个评论
postNewComment(): Promise<TopicCreateCommentResponseData> {
return new Promise((resolve, reject) => {
const requestData: TopicCreateCommentRequestData = {
tid: this.commentDraft.tid,
rid: this.commentDraft.rid,
to_uid: this.commentDraft.to_uid,
content: this.commentDraft.content,
}
postCommentByPidAndRidApi(requestData)
.then((res) => {
resolve(res)
})
.catch((error) => {
reject(error)
})
})
async postNewComment(): Promise<TopicCreateCommentResponseData> {
const requestData: TopicCreateCommentRequestData = {
tid: this.commentDraft.tid,
rid: this.commentDraft.rid,
to_uid: this.commentDraft.to_uid,
content: this.commentDraft.content,
}
return await postCommentByPidAndRidApi(requestData)
},
// 设置回复草稿为原始值,用于回复发布按钮
resetReplyDraft() {
this.replyDraft.textCount = 0

View file

@ -15,7 +15,7 @@ interface TopicRewrite {
isTopicRewriting: boolean
}
export interface Topic {
export interface EditStore {
/**
*
* @param {number} editorHeight -

17
src/store/types/home.d.ts vendored Normal file
View file

@ -0,0 +1,17 @@
export interface HomeStore {
keywords: string
category: string
page: number
limit: number
sortField: string
sortOrder: string
// 加载完了是否还需要加载
isLoading: boolean
// 其它的 store
// 是否激活主页的左侧交互面板
isActiveMainPageAside: boolean
// 搜索历史存储
searchHistory: string[]
}

7
src/store/types/kungalgamer.d.ts vendored Normal file
View file

@ -0,0 +1,7 @@
// 用户信息接口
export interface KUNGalgamerStore {
uid: number
name: string
avatar: string
moemoeAccessToken: string
}

20
src/store/types/message.d.ts vendored Normal file
View file

@ -0,0 +1,20 @@
export interface MessageStore {
// 是否展示通知消息
showInfo: boolean
// 是否展示警告消息
showAlert: boolean
// 通知消息的内容
infoMsg: string
// 警告消息的内容
alertMsg: string
// 是否展示取消按钮Alert 组件专用
isShowCancel: boolean
// 返回确认信息Alert 组件专用
confirm: boolean
// 人机验证组件
// 是否显示人机验证
isShowCapture: boolean
// 是否验证通过
isCaptureSuccessful: boolean
}

18
src/store/types/settings.d.ts vendored Normal file
View file

@ -0,0 +1,18 @@
// 设置面板配置
export interface KUNGalgameSettingsStore {
// 白天黑夜模式切换
showKUNGalgameMode: string
// 网站显示语言
showKUNGalgameLanguage: string
// 主页宽度
showKUNGalgamePageWidth: Record<string, number>
// 网站字体
showKUNGalgameFontStyle: string
// 背景图
showKUNGalgameBackground: string
// 自定义背景图
showKUNGalgameCustomBackground: string
// 显示页面宽度还是显示字体设置
isShowPageWidth: boolean
}

80
src/store/types/topic.d.ts vendored Normal file
View file

@ -0,0 +1,80 @@
// 回复的缓存
interface ReplyDraft {
/**
*
* @param {number} editorHeight -
* @param {'' | 'essential' | 'minimal' | 'full'} mode - toolbar
* @param {'snow' | 'bubble'} theme -
*/
editorHeight: number
textCount: number
// 这里仅支持三种模式
mode: '' | 'essential' | 'minimal'
theme: 'snow' | 'bubble'
// 是否显示热门关键词
isShowHotKeywords: boolean
// 当前话题的 id
tid: number
r_uid: number
// 回复给谁,用于回复面板展示
replyUserName: string
to_uid: number
content: string
tags: string[]
// 被回复的人的楼层数,用于跳转
to_floor: number
// 是否保存回复
isSaveReply: boolean
// 回复发布的状态,如果状态有变化则将发布好的回复数据添加在回复数组里
// 这里与 true 和 false 无关,关心的是它的状态改变
publishStatus: boolean
}
// 获取回复的请求
interface ReplyRequest {
page: number
limit: number
sortField: string
sortOrder: 'asc' | 'desc'
}
// 评论的缓存
interface CommentDraft {
// 评论的内容
tid: number
rid: number
c_uid: number
to_uid: number
content: string
// 显示哪个评论的评论面板
isShowCommentPanelRid: number
}
// 话题页面的 store
export interface TopicStore {
// 是否正在被编辑
isEdit: boolean
// 是否显示高级编辑模式
isShowAdvance: boolean
// 是否激活左侧交互面板
isActiveAside: boolean
// 是否滚动到顶部
isScrollToTop: boolean
// 加载完了是否还需要加载
isLoading: boolean
// 要滚动到的回复 id
scrollToReplyId: number
// 回复面板的宽度
replyPanelWidth: number
// 回复的缓存
replyDraft: ReplyDraft
// 获取回复的请求接口格式
replyRequest: ReplyRequest
// 评论的缓存
commentDraft: CommentDraft
}

View file

@ -1,15 +1,24 @@
// api 请求格式
import { EditCreateTopicRequestData } from '@/api'
import { EditCreateTopicRequestData, EditUpdateTopicRequestData } from '@/api'
// 全局消息组件(顶部)
import message from '@/components/alert/Message'
// 类型守卫,确定 EditUpdateTopicRequestData 含有 tid
const isEditUpdateTopicData = (data: any): data is EditUpdateTopicRequestData =>
typeof data.tid !== 'undefined'
// 发布时检测用户输入是否合法
export const checkTopicPublish = (
textCount: number,
topicData: EditCreateTopicRequestData
topicData: EditCreateTopicRequestData | EditUpdateTopicRequestData
) => {
if (!topicData.title.trim()) {
if (isEditUpdateTopicData(topicData)) {
// 话题 id 为零,应该。。。。不存在吧(
if (!topicData.tid) {
message('Failed to resolve topic', '未能解析话题 ID', 'error')
}
} else if (!topicData.title.trim()) {
// 标题为空的话,警告
message('Title cannot be empty!', '标题不可为空!', 'warn')
return false

View file

@ -28,3 +28,9 @@ button,
select {
font-family: inherit;
}
/* 鼠标选中文字的颜色 */
*::selection {
background-color: var(--kungalgame-blue-1); /* 选中文本的背景颜色 */
color: var(--kungalgame-blue-4); /* 选中文本的文本颜色 */
}