- Login.vue: 删除多余的 else 分支(拦截器已处理错误) - Hitokoto.vue/Music.vue/SystemConfig.vue/SystemRole.vue/SystemUser.vue: - ElMessage.success 使用固定中文提示替代 data.message - 删除未使用的 data 变量 - SourceImage.vue/Article.vue: response.status → response.code === 0 统一接口响应格式后的代码优化。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
149 lines
5.1 KiB
Vue
149 lines
5.1 KiB
Vue
<template>
|
|
<div class="page-wrapper">
|
|
<el-form inline :model="search">
|
|
<el-form-item label="内容">
|
|
<el-input v-model="search.hitokoto" />
|
|
</el-form-item>
|
|
<el-form-item label="类型">
|
|
<el-select v-model="search.types" multiple collapse-tags>
|
|
<el-option v-for="item in typeList" :key="item.value" :value="item.value" :label="item.label" />
|
|
</el-select>
|
|
</el-form-item>
|
|
<el-form-item label="创建时间">
|
|
<el-date-picker
|
|
v-model="search.createdAt"
|
|
type="daterange"
|
|
range-separator="至"
|
|
start-placeholder="开始日期"
|
|
end-placeholder="结束日期" />
|
|
</el-form-item>
|
|
</el-form>
|
|
<div class="btn-container">
|
|
<el-button type="primary" @click="addModal = true">添加</el-button>
|
|
<el-button type="danger" @click="deleteAll">删除</el-button>
|
|
<div class="search-btn">
|
|
<el-button type="primary" @click="loadDataBase(true)" icon="Search">搜索</el-button>
|
|
<el-button @click="reset" icon="RefreshLeft">重置</el-button>
|
|
</div>
|
|
</div>
|
|
<div class="table-container">
|
|
<el-table :data="hitokotoData" v-loading="loading" stripe @selection-change="dataSelect">
|
|
<el-table-column type="selection" width="55" />
|
|
<el-table-column prop="type" label="类型" width="180">
|
|
<template #default="scope">
|
|
{{ findTypeText(scope.row.type) }}
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column prop="hitokoto" label="内容" />
|
|
<el-table-column prop="from" label="来自" width="180"/>
|
|
<el-table-column prop="creator" label="作者" width="180"/>
|
|
<el-table-column prop="number" label="编号" width="70"/>
|
|
<el-table-column prop="createdAt" label="创建时间" width="180">
|
|
<template #default="scope">
|
|
{{ datetimeFormat(scope.row.createdAt) }}
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
</div>
|
|
<div class="page-container">
|
|
<el-pagination background
|
|
:page-sizes="store.state.pageSizeOpts"
|
|
:layout="store.state.pageLayout"
|
|
:current-page="search.pageNum"
|
|
:total="total"
|
|
@size-change="pageSizeChange"
|
|
@current-change="pageChange">
|
|
</el-pagination>
|
|
</div>
|
|
<el-dialog v-model="addModal" title="新增一言" >
|
|
<hitokoto-add ref="addForm" :typeList="typeList" :formData="formData" />
|
|
<template #footer>
|
|
<span class="dialog-footer">
|
|
<el-button @click="addModal = false">取消</el-button>
|
|
<el-button type="primary" @click="save" :loading="modalLoading">确定</el-button>
|
|
</span>
|
|
</template>
|
|
</el-dialog>
|
|
</div>
|
|
</template>
|
|
<script setup lang="ts">
|
|
import { ref, reactive } from 'vue'
|
|
import { useStore } from 'vuex'
|
|
import HitokotoAdd from './HitokotoAdd.vue'
|
|
import { useBaseList } from '@/model/baselist'
|
|
import { Page } from '@/model/common.dto'
|
|
import HitokotoModel from '@/model/api/hitokoto'
|
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
import http from '@/utils/http'
|
|
|
|
class HitokotoPage extends Page {
|
|
hitokoto?: string
|
|
types?: string[]
|
|
createdAt?: [Date, Date]
|
|
reset() {
|
|
super.reset()
|
|
this.hitokoto = undefined
|
|
this.types = []
|
|
this.createdAt = undefined
|
|
}
|
|
}
|
|
|
|
const store = useStore()
|
|
const { loading, modalLoading, total, search, setLoadData, loadDataBase, reset, pageChange, pageSizeChange, datetimeFormat } = useBaseList(new HitokotoPage())
|
|
|
|
const typeList = ref<{label: string, value: string}[]>([])
|
|
const hitokotoData = ref<HitokotoModel[]>([])
|
|
const formData = reactive<{[propName: string]: string | null}>({})
|
|
const addModal = ref(false)
|
|
const addForm = ref<InstanceType<typeof HitokotoAdd>>()
|
|
|
|
let selectedData: string[] = []
|
|
|
|
async function loadData() {
|
|
loading.value = true
|
|
const data = await http.get<HitokotoPage, any>('/api/v2/hitokoto/list', {params: search})
|
|
selectedData = []
|
|
loading.value = false
|
|
total.value = data.total
|
|
hitokotoData.value = data.list
|
|
}
|
|
setLoadData(loadData)
|
|
|
|
async function save() {
|
|
addForm.value?.hitokotoForm?.validate(async (valid: boolean) => {
|
|
if (!valid) return
|
|
modalLoading.value = true
|
|
const data = await http.post<any, any>('/api/v2/hitokoto/save', formData)
|
|
modalLoading.value = false
|
|
addModal.value = false
|
|
ElMessage.success('保存成功')
|
|
loadData()
|
|
Object.keys(formData).forEach(key => delete formData[key])
|
|
})
|
|
}
|
|
function deleteAll() {
|
|
if (!selectedData.length) {
|
|
ElMessage.warning('请选择要删除的数据')
|
|
return
|
|
}
|
|
ElMessageBox.confirm(`是否确认删除选中的${selectedData.length}条数据?`, '确认删除', {type: 'warning'}).then(async () => {
|
|
await http.delete<any, any>('/api/v2/hitokoto/delete', {params: {_ids: selectedData}})
|
|
ElMessage.success('删除成功')
|
|
loadData()
|
|
}).catch(() => {})
|
|
}
|
|
function dataSelect(selection: HitokotoModel[]) {
|
|
selectedData = selection.map(item => item._id)
|
|
}
|
|
function findTypeText(value: string): string | null {
|
|
const type = typeList.value.find(item => item.value === value)
|
|
return type ? type.label : null
|
|
}
|
|
|
|
// created
|
|
loadData()
|
|
http.get<never, any>('/api/v2/common/config/hitokoto_type').then(data => {
|
|
typeList.value = data
|
|
})
|
|
</script>
|