FssAdmin PHP 版发布到 V1.1.0,这次更新继续开源文章管理模块。对正在做 OA、ERM、ERP、政务系统或中小型业务后台的团队来说,这类项目的价值不在于“技术栈够新”本身,而在于它能不能把登录、菜单、权限、表格、表单、状态持久化这些日常工作压缩成可复用的工程骨架。
FssAdmin 的前端栈选择了 Vue3、Vite、TypeScript、Pinia、Pinia 持久化插件、UnoCSS 和 Element Plus。相比一些功能堆得很满的后台模板,它强调简洁、快捷、容易理解,这一点对中小项目尤其关键:后台系统通常不是难在某一个组件,而是难在模块一多之后还能不能维护。
这次 V1.1.0 值得关注的点
V1.1.0 的明确变化是继续开源了文章管理模块。文章管理在后台系统里看似普通,但它通常会牵出一整套典型 CRUD 能力:列表查询、状态切换、分类或标签、富文本内容、发布流程、权限控制、编辑回显。
如果一个后台模板把文章模块做成清晰的示例,开发者就可以把它当作“业务模块样板”:把字段换成客户、合同、工单、公告、政策文件,保留列表页、编辑页、接口封装、路由注册、权限点等结构。这比只给一个空壳管理台更容易落地。
需要注意的是,来源摘要只明确提到“继续开源了文章管理模块”,没有展开模块的全部功能细节。因此在评估时,不应默认它已经覆盖复杂工作流,例如多级审核、草稿版本对比、全文检索、附件归档等能力。这些更适合在拿到源码后按业务补齐。
技术栈的取舍:不是炫技,而是降低后台维护成本
Vue3 和 Vite 解决的是开发体验和构建速度问题。后台系统页面多、表单多、调试频繁,冷启动和热更新速度会直接影响迭代效率。
TypeScript 的价值在后台里也很实在。接口字段、表单模型、列表查询参数、菜单结构,一旦没有类型约束,后期改字段很容易变成运行时错误。Pinia 则承担用户信息、权限、菜单、标签页、主题配置等全局状态。配合持久化插件,可以把登录态、界面偏好、部分缓存状态保存在本地,刷新页面后不用重新组织所有上下文。
UnoCSS 和 Element Plus 的组合也比较符合管理系统的诉求。Element Plus 提供稳定的表格、表单、弹窗、分页、日期选择器;UnoCSS 适合快速处理间距、布局和局部样式。只要团队约束好样式写法,就能避免后台页面越写越散。
可以这样实践:给文章管理补一个类型安全的 Pinia 查询状态
下面这个例子不是来源声称的内置代码,而是基于 FssAdmin 技术栈可以采用的一种实践方式:把文章列表页的查询条件放进 Pinia,并用持久化插件保存。这样用户从编辑页返回列表时,分页、关键词、状态筛选不会丢。
你可以把它改造成 src/stores/articleQuery.ts,字段名按实际接口调整。
import { defineStore } from 'pinia'
export type ArticleStatus = 'all' | 'draft' | 'published' | 'disabled'
export interface ArticleQueryState {
keyword: string
status: ArticleStatus
page: number
pageSize: number
}
export const useArticleQueryStore = defineStore('articleQuery', {
state: (): ArticleQueryState => ({
keyword: '',
status: 'all',
page: 1,
pageSize: 20
}),
actions: {
setKeyword(keyword: string) {
this.keyword = keyword.trim()
this.page = 1
},
setStatus(status: ArticleStatus) {
this.status = status
this.page = 1
},
setPage(page: number) {
this.page = page
},
reset() {
this.keyword = ''
this.status = 'all'
this.page = 1
this.pageSize = 20
}
},
persist: true
})
如果你的项目还没有注册 Pinia 持久化插件,可以参考下面的入口配置。实际文件名通常是 main.ts,请按项目结构调整导入路径。
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
import App from './App.vue'
const app = createApp(App)
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
app.use(pinia)
app.mount('#app')
在文章列表页里可以这样使用:
<script setup lang="ts">
import { storeToRefs } from 'pinia'
import { useArticleQueryStore } from '@/stores/articleQuery'
const queryStore = useArticleQueryStore()
const { keyword, status, page, pageSize } = storeToRefs(queryStore)
async function loadArticles() {
const params = {
keyword: keyword.value,
status: status.value === 'all' ? undefined : status.value,
page: page.value,
pageSize: pageSize.value
}
console.log('replace with real article API params:', params)
}
</script>
<template>
<el-form inline @submit.prevent>
<el-form-item label="关键词">
<el-input
:model-value="keyword"
clearable
placeholder="标题或摘要"
@update:model-value="queryStore.setKeyword"
/>
</el-form-item>
<el-form-item label="状态">
<el-select :model-value="status" style="width: 140px" @update:model-value="queryStore.setStatus">
<el-option label="全部" value="all" />
<el-option label="草稿" value="draft" />
<el-option label="已发布" value="published" />
<el-option label="已禁用" value="disabled" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="loadArticles">查询</el-button>
<el-button @click="queryStore.reset(); loadArticles()">重置</el-button>
</el-form-item>
</el-form>
</template>
这段代码的重点不是“多写一个 store”,而是把后台页面最容易散落的状态收拢起来。列表页、编辑页、返回导航、标签页缓存都可以围绕同一个查询状态工作。
本地接入时先跑通这几件事
拿到 FssAdmin 源码后,可以按类似流程验证前端工程是否健康。命令中的包管理器以 pnpm 为例,如果项目锁文件使用 npm 或 yarn,就换成对应命令。
pnpm install
pnpm dev
pnpm type-check
pnpm build
如果项目提供环境变量模板,可以复制一份本地配置:
cp .env.example .env.local
然后重点检查几个变量:
VITE_APP_TITLE=FssAdmin
VITE_API_BASE_URL=http://127.0.0.1:8000
这里的 VITE_API_BASE_URL 要改成你的 PHP 后端实际地址。生产环境不要直接复用本地地址,也不要把测试接口、调试开关和临时 token 写进仓库。
适合谁采用,哪里要谨慎
FssAdmin 这种简洁型中后台更适合两类场景:一类是中小型业务系统,需要快速搭出可维护的菜单、权限、表格和表单;另一类是个人或团队内部项目,希望少一点模板噪音,多一点能直接改的代码。
如果你的系统已经有复杂的组织权限、流程引擎、数据隔离、审计留痕、国际化、多租户要求,就不要只看模板页面是否漂亮。更应该检查后端权限模型、接口规范、错误处理、日志、部署方式,以及文章管理这类示例模块能否扩展成你的真实业务模块。
一个务实的采用清单是:先跑通登录和菜单,再读文章管理模块的目录结构,然后复制出一个最小业务模块,接入真实接口,最后补类型检查和构建验证。模板的价值不在于替你完成业务,而在于让团队从第一天就站在一套清楚的工程结构上开发。