feat: separate editor store
This commit is contained in:
parent
e3e67f9156
commit
051a031831
|
@ -16,13 +16,8 @@ const EditorSettingsMenu = defineAsyncComponent(
|
|||
import 'animate.css'
|
||||
|
||||
// 接受传入的编辑器计数
|
||||
/**
|
||||
* @param {number} - 编辑器文字计数
|
||||
* @param {boolean} - 是否显示编辑器设置
|
||||
*/
|
||||
defineProps<{
|
||||
textCount: number
|
||||
isShowSettings: boolean
|
||||
}>()
|
||||
|
||||
const router = useRouter()
|
||||
|
@ -60,7 +55,6 @@ const handelClickSettings = () => {
|
|||
@click="handelClickSettings"
|
||||
class="settings-icon"
|
||||
:class="settingsPanelActive"
|
||||
v-if="isShowSettings"
|
||||
>
|
||||
<Icon icon="uiw:setting-o" />
|
||||
</span>
|
||||
|
|
|
@ -1,33 +1,48 @@
|
|||
<script setup lang="ts">
|
||||
import { ref, watch } from 'vue'
|
||||
import { ref, watch, computed } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
// 引入 css 动画
|
||||
import 'animate.css'
|
||||
|
||||
// 导入编辑话题的 store
|
||||
import { useKUNGalgameEditStore } from '@/store/modules/edit'
|
||||
// 导入回复的 store
|
||||
import { useKUNGalgameTopicStore } from '@/store/modules/topic'
|
||||
import { storeToRefs } from 'pinia'
|
||||
|
||||
// 导入关键词显示切换按钮
|
||||
import SwitchButton from './SwitchButton.vue'
|
||||
|
||||
// 使用编辑界面的 store
|
||||
const settingsStore = useKUNGalgameEditStore()
|
||||
const { mode } = storeToRefs(settingsStore)
|
||||
|
||||
const { editorHeight } = storeToRefs(useKUNGalgameEditStore())
|
||||
// 话题编辑界面 store
|
||||
const { editorHeight, mode } = storeToRefs(useKUNGalgameEditStore())
|
||||
// 话题界面的 store,用于回复
|
||||
const { replyDraft } = storeToRefs(useKUNGalgameTopicStore())
|
||||
|
||||
defineProps<{
|
||||
isShowSettingsMenu: boolean
|
||||
}>()
|
||||
|
||||
// 当前的路由
|
||||
const route = useRoute()
|
||||
// 当前页面路由的名字
|
||||
const routeName = computed(() => route.name as string)
|
||||
|
||||
// 编辑器的模式
|
||||
const editorMode = computed(() =>
|
||||
routeName.value === 'Edit' ? mode.value : replyDraft.value.mode
|
||||
)
|
||||
|
||||
// 是否显示刷新页面
|
||||
const isRefreshPage = ref(false)
|
||||
|
||||
// 点击高级选项时提醒用户刷新页面
|
||||
watch(mode, () => {
|
||||
isRefreshPage.value = true
|
||||
})
|
||||
watch(
|
||||
() => [replyDraft.value.mode, mode.value],
|
||||
() => {
|
||||
isRefreshPage.value = true
|
||||
}
|
||||
)
|
||||
|
||||
const handleRefreshPage = () => location.reload()
|
||||
</script>
|
||||
|
@ -44,7 +59,9 @@ const handleRefreshPage = () => location.reload()
|
|||
<span> {{ $tm('edit.editorHeight') }} </span>
|
||||
<span>{{ editorHeight }} px</span>
|
||||
</div>
|
||||
<div class="editor-height">
|
||||
|
||||
<!-- 编辑界面 -->
|
||||
<div v-if="routeName === 'Edit'" class="editor-height">
|
||||
<span>300 px</span>
|
||||
<input
|
||||
type="range"
|
||||
|
@ -56,6 +73,19 @@ const handleRefreshPage = () => location.reload()
|
|||
<span>500 px</span>
|
||||
</div>
|
||||
|
||||
<!-- 回复面板 -->
|
||||
<div v-if="routeName === 'Topic'" class="editor-height">
|
||||
<span>100 px</span>
|
||||
<input
|
||||
type="range"
|
||||
min="100"
|
||||
max="500"
|
||||
step="1"
|
||||
v-model="replyDraft.editorHeight"
|
||||
/>
|
||||
<span>500 px</span>
|
||||
</div>
|
||||
|
||||
<!-- 是否显示编辑器高级选项 -->
|
||||
<div class="editor-advance">
|
||||
<div class="editor-advance-title">
|
||||
|
@ -72,7 +102,7 @@ const handleRefreshPage = () => location.reload()
|
|||
</div>
|
||||
|
||||
<!-- 切换按钮 -->
|
||||
<select class="select" v-model="mode">
|
||||
<select class="select" v-model="editorMode">
|
||||
<option value="minimal">{{ $tm('edit.minimal') }}</option>
|
||||
<option value="">{{ $tm('edit.default') }}</option>
|
||||
<option value="essential">{{ $tm('edit.essential') }}</option>
|
||||
|
|
|
@ -30,9 +30,8 @@ import DOMPurify from 'dompurify'
|
|||
import { debounce } from '@/utils/debounce'
|
||||
|
||||
// 话题编辑界面 store
|
||||
const { editorHeight, mode, theme, isSaveTopic, content } = storeToRefs(
|
||||
useKUNGalgameEditStore()
|
||||
)
|
||||
const { editorHeight, mode, theme, textCount, isSaveTopic, content } =
|
||||
storeToRefs(useKUNGalgameEditStore())
|
||||
// 话题界面的 store,用于回复
|
||||
const { replyDraft } = storeToRefs(useKUNGalgameTopicStore())
|
||||
|
||||
|
@ -43,7 +42,6 @@ const routeName = computed(() => route.name as string)
|
|||
|
||||
// 定义父组件传参
|
||||
/**
|
||||
* @param {number} height - 编辑器的高度
|
||||
* @param {boolean} isShowToolbar - 是否显示工具栏
|
||||
* @param {boolean} isShowAdvance - 是否显示高级编辑模式
|
||||
* @param {boolean} isShowTitle - 是否显示标题
|
||||
|
@ -51,7 +49,6 @@ const routeName = computed(() => route.name as string)
|
|||
*/
|
||||
|
||||
const props = defineProps<{
|
||||
height?: number
|
||||
isShowToolbar: boolean
|
||||
isShowAdvance: boolean
|
||||
isShowTitle: boolean
|
||||
|
@ -60,28 +57,37 @@ const props = defineProps<{
|
|||
|
||||
// 编辑器实例
|
||||
const editorRef = ref<typeof QuillEditor>()
|
||||
|
||||
// 编辑器的高度
|
||||
const editorHeightStyle = computed(
|
||||
() => `height: ${props.height ? props.height : editorHeight.value}px`
|
||||
)
|
||||
// 编辑器的工具栏是否显示
|
||||
const isShowEditorToolbar = computed(() =>
|
||||
props.isShowToolbar ? 'block' : 'none'
|
||||
)
|
||||
|
||||
// 编辑器内的内容
|
||||
const valueHtml = ref('')
|
||||
// 编辑器文字计数
|
||||
const textCount = ref(0)
|
||||
|
||||
// 编辑器相关配置
|
||||
const editorOptions = {
|
||||
placeholder: 'Moe Moe Moe!',
|
||||
}
|
||||
|
||||
// 编辑器实例创建时
|
||||
const onEditorReady = () => {}
|
||||
// 编辑器的高度,根据路由的名字确定
|
||||
const editorHeightStyle = computed(
|
||||
() =>
|
||||
`height: ${
|
||||
routeName.value === 'Edit'
|
||||
? editorHeight.value
|
||||
: replyDraft.value.editorHeight
|
||||
}px`
|
||||
)
|
||||
|
||||
// 编辑器的模式,根据路由的名字确定
|
||||
const editorMode = computed(() =>
|
||||
routeName.value === 'Edit' ? mode.value : replyDraft.value.mode
|
||||
)
|
||||
|
||||
// 编辑器的文字计数,根据路由的名字确定
|
||||
const textCountNumber = computed(() =>
|
||||
routeName.value === 'Edit' ? textCount.value : replyDraft.value.textCount
|
||||
)
|
||||
|
||||
// 编辑器的工具栏是否显示
|
||||
const isShowEditorToolbar = computed(() =>
|
||||
props.isShowToolbar ? 'block' : 'none'
|
||||
)
|
||||
|
||||
onBeforeMount(() => {
|
||||
// 挂载之前载入话题数据,如果不保存,则不载入(并且当前必须在 Edit 界面)
|
||||
|
@ -115,7 +121,14 @@ const handleTextChange = async () => {
|
|||
|
||||
// 计算用户输入了多少个字符
|
||||
const length = computed(() => editorRef.value?.getText().trim().length)
|
||||
textCount.value = length.value
|
||||
|
||||
// 根据页面的路由名保存计数
|
||||
if (routeName.value === 'Edit') {
|
||||
textCount.value = length.value
|
||||
}
|
||||
if (routeName.value === 'Topic') {
|
||||
replyDraft.value.textCount = length.value
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -132,19 +145,14 @@ const handleTextChange = async () => {
|
|||
:style="editorHeightStyle"
|
||||
:theme="theme"
|
||||
:modules="modules"
|
||||
:toolbar="mode"
|
||||
:toolbar="editorMode"
|
||||
:options="editorOptions"
|
||||
@textChange="handleTextChange"
|
||||
@ready="onEditorReady"
|
||||
@click.prevent
|
||||
/>
|
||||
|
||||
<!-- 编辑器 footer -->
|
||||
<EditorFooter
|
||||
:textCount="textCount"
|
||||
:editorHeight="editorHeight"
|
||||
:isShowSettings="isShowSettings"
|
||||
/>
|
||||
<EditorFooter :textCount="textCountNumber" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -1,26 +1,49 @@
|
|||
<!-- KUNGalgame 通用切换按钮 -->
|
||||
|
||||
<script setup lang="ts">
|
||||
import { watch } from 'vue'
|
||||
import { watch, computed } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
// 导入编辑界面 store
|
||||
import { useKUNGalgameEditStore } from '@/store/modules/edit'
|
||||
// 导入回复的 store
|
||||
import { useKUNGalgameTopicStore } from '@/store/modules/topic'
|
||||
import { storeToRefs } from 'pinia'
|
||||
|
||||
// 当前页面的路由
|
||||
const route = useRoute()
|
||||
// 当前页面路由的名字
|
||||
const routeName = computed(() => route.name as string)
|
||||
|
||||
// 使用编辑界面的 store
|
||||
const settingsStore = useKUNGalgameEditStore()
|
||||
const { isShowHotKeywords } = storeToRefs(settingsStore)
|
||||
const { isShowHotKeywords } = storeToRefs(useKUNGalgameEditStore())
|
||||
// 话题界面的 store,用于回复
|
||||
const { replyDraft } = storeToRefs(useKUNGalgameTopicStore())
|
||||
|
||||
// 监听 store 中的状态变化,保持按钮状态与 store 同步
|
||||
watch(isShowHotKeywords, (newValue) => {
|
||||
isShowHotKeywords.value = newValue
|
||||
})
|
||||
watch(
|
||||
() => [isShowHotKeywords.value, replyDraft.value.isShowHotKeywords],
|
||||
([newValue1, newValue2]) => {
|
||||
isShowHotKeywords.value = newValue1
|
||||
replyDraft.value.isShowHotKeywords = newValue2
|
||||
}
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<input type="checkbox" id="switch" v-model="isShowHotKeywords" /><label
|
||||
for="switch"
|
||||
>Toggle</label
|
||||
>
|
||||
<!-- 根据路由名绑定不同的 model -->
|
||||
<input
|
||||
v-if="routeName === 'Edit'"
|
||||
type="checkbox"
|
||||
id="switch"
|
||||
v-model="isShowHotKeywords"
|
||||
/>
|
||||
<input
|
||||
v-if="routeName === 'Topic'"
|
||||
type="checkbox"
|
||||
id="switch"
|
||||
v-model="replyDraft.isShowHotKeywords"
|
||||
/>
|
||||
<label for="switch"></label>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
|
|
@ -98,7 +98,7 @@ export default {
|
|||
panel: {
|
||||
to: 'Reply To',
|
||||
master: 'ご主人',
|
||||
reply: 'zako♡',
|
||||
reply: 'zako~♡',
|
||||
},
|
||||
},
|
||||
update: {
|
||||
|
|
|
@ -14,6 +14,7 @@ interface Topic {
|
|||
* @param {'snow' | 'bubble'} theme - 编辑器主题
|
||||
*/
|
||||
editorHeight: number
|
||||
textCount: number
|
||||
mode: '' | 'essential' | 'minimal' | 'full'
|
||||
theme: 'snow' | 'bubble'
|
||||
|
||||
|
@ -44,6 +45,7 @@ export const useKUNGalgameEditStore = defineStore({
|
|||
persist: true,
|
||||
state: (): Topic => ({
|
||||
editorHeight: 300,
|
||||
textCount: 0,
|
||||
mode: '',
|
||||
theme: 'snow',
|
||||
|
||||
|
|
|
@ -21,6 +21,19 @@ import {
|
|||
|
||||
// 回复的缓存
|
||||
interface ReplyDraft {
|
||||
/**
|
||||
* 编辑器相关
|
||||
* @param {number} editorHeight - 编辑器高度
|
||||
* @param {'' | 'essential' | 'minimal' | 'full'} mode - 编辑器 toolbar 模式
|
||||
* @param {'snow' | 'bubble'} theme - 编辑器主题
|
||||
*/
|
||||
editorHeight: number
|
||||
textCount: number
|
||||
mode: '' | 'essential' | 'minimal' | 'full'
|
||||
theme: 'snow' | 'bubble'
|
||||
// 是否显示热门关键词
|
||||
isShowHotKeywords: boolean
|
||||
|
||||
// 当前话题的 id
|
||||
tid: number
|
||||
r_uid: number
|
||||
|
@ -90,6 +103,12 @@ export const useKUNGalgameTopicStore = defineStore({
|
|||
scrollToReplyId: -1,
|
||||
|
||||
replyDraft: {
|
||||
editorHeight: 200,
|
||||
textCount: 0,
|
||||
mode: '',
|
||||
theme: 'snow',
|
||||
isShowHotKeywords: true,
|
||||
|
||||
tid: 0,
|
||||
r_uid: 0,
|
||||
replyUserName: '',
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import { ref, computed, watch, onBeforeMount, onUpdated } from 'vue'
|
||||
import { ref, computed, watch, onBeforeMount } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
// 导入编辑话题的 store
|
||||
import { useKUNGalgameEditStore } from '@/store/modules/edit'
|
||||
|
@ -18,6 +18,13 @@ const { isShowHotKeywords, tags, isSaveTopic } = storeToRefs(
|
|||
// 话题界面的 store,用于回复
|
||||
const { replyDraft } = storeToRefs(useKUNGalgameTopicStore())
|
||||
|
||||
// 根据路由名计算是否展示热门 tags
|
||||
const isShowKeywords = computed(() =>
|
||||
routeName.value === 'Edit'
|
||||
? isShowHotKeywords.value
|
||||
: replyDraft.value.isShowHotKeywords
|
||||
)
|
||||
|
||||
// 临时数据,将会从后端返回 7 个热门 tag
|
||||
const hotTags = [
|
||||
'啊这可海星',
|
||||
|
@ -143,7 +150,7 @@ watch(selectedTags.value, () => {
|
|||
<div class="hint">{{ $tm('edit.hint') }}</div>
|
||||
|
||||
<!-- 热门 tags -->
|
||||
<div class="hot-tags" v-if="isShowHotKeywords">
|
||||
<div class="hot-tags" v-if="isShowKeywords">
|
||||
<!-- 标签的提示词 -->
|
||||
<div class="tags-info">{{ $tm('edit.hot') }}</div>
|
||||
<!-- 标签容器 -->
|
||||
|
|
|
@ -15,21 +15,34 @@ const { isShowAdvance, replyDraft, isEdit } = storeToRefs(
|
|||
const info = useKUNGalgameMessageStore()
|
||||
|
||||
// 检查回复是否合法
|
||||
const isValidReply = () => {}
|
||||
const isValidReply = () => {
|
||||
return replyDraft.value.content.trim().length > 7 &&
|
||||
replyDraft.value.content.trim() !== `<p><br></p>`
|
||||
? true
|
||||
: false
|
||||
}
|
||||
|
||||
// 发布回复的函数
|
||||
const publishReply = async () => {
|
||||
// 重置页数,是否加载等页面状态
|
||||
useKUNGalgameTopicStore().resetPageStatus()
|
||||
// 发布回复
|
||||
await useKUNGalgameTopicStore().postNewReply()
|
||||
if (isValidReply()) {
|
||||
console.log(replyDraft.value.content)
|
||||
|
||||
// 改变发布状态,前端会新增回复的数据
|
||||
replyDraft.value.publishStatus = !replyDraft.value.publishStatus
|
||||
// 取消保存
|
||||
useKUNGalgameTopicStore().resetReplyDraft()
|
||||
// 关闭面板
|
||||
isEdit.value = false
|
||||
// 重置页数,是否加载等页面状态
|
||||
useKUNGalgameTopicStore().resetPageStatus()
|
||||
// 发布回复
|
||||
await useKUNGalgameTopicStore().postNewReply()
|
||||
|
||||
// 改变发布状态,前端会新增回复的数据
|
||||
replyDraft.value.publishStatus = !replyDraft.value.publishStatus
|
||||
// 取消保存
|
||||
useKUNGalgameTopicStore().resetReplyDraft()
|
||||
// 关闭面板
|
||||
isEdit.value = false
|
||||
// 发布成功提示
|
||||
message('Publish reply successfully!', '发布回复成功!', 'success')
|
||||
} else {
|
||||
message('Reply content cannot be empty!', '回复内容不能为空!', 'warn')
|
||||
}
|
||||
}
|
||||
|
||||
// 点击发布回复
|
||||
|
@ -38,8 +51,6 @@ const handlePublish = async () => {
|
|||
// 这里实现用户的点击确认取消逻辑
|
||||
if (res) {
|
||||
publishReply()
|
||||
// 发布成功提示
|
||||
message('Publish reply successfully!', '发布回复成功!', 'success')
|
||||
} else {
|
||||
// 取消发布提示
|
||||
message('Cancel publish reply', '取消发布回复', 'info')
|
||||
|
|
Loading…
Reference in a new issue