vue2-business-development
14
总安装量
9
周安装量
#23886
全站排名
安装命令
npx skills add https://github.com/levai/zl-skills --skill vue2-business-development
Agent 安装分布
cursor
7
trae-cn
2
claude-code
2
trae
1
opencode
1
continue
1
Skill 文档
ä¸å¡å¼å宿´æå
使¶ä½¿ç¨
å½éè¦å¼åæ°ä¸å¡åè½æå建æ°ä¸å¡æ¨¡åæ¶ä½¿ç¨æ¤æè½ï¼å æ¬ï¼
- å建æ°çä¸å¡æ¨¡åï¼å¦æ°æ®èµäº§ç®¡çãæ°æ®è´¨éçï¼
- å¼åæ°ç CRUD 页é¢
- å®ç°ä¸å¡åè½éæ±
- æ·»å æ°çè·¯ç±åèå
- å建 Vuex store åç»ä»¶
å¼åæµç¨æ¦è§
1. çè§£éæ± â 2. è®¾è®¡æ°æ®ç»æ â 3. åå»ºè·¯ç± â 4. å建 Store â 5. å建è§å¾ç»ä»¶ â 6. å®ç°ä¸å¡é»è¾ â 7. æµè¯ä¸æäº¤
å¿«éå¼å§
1. å建æ°ä¸å¡æ¨¡å
æ¥éª¤ 1: æ·»å è·¯ç±é ç½®
å¨ src/router/routes/ ç®å½ä¸å建模åè·¯ç±æä»¶ï¼
// src/router/routes/myModule/index.ts
import { RouteConfig } from '@/router/types'
import { Layout } from '@/layout'
import { PidValue } from '@/router/constant'
// 模åé¦é¡µ
export const MyModuleOverview: RouteConfig = {
path: 'myModule',
component: Layout,
meta: {
name: 'My Module',
icon: 'top-nav-icon',
globalKey: 'myModule',
globalModel: 'myModule',
pid: PidValue.UNKNOWN
},
children: [
{
path: 'overview',
component: () => import('@/views/myModule/overview/index.vue'),
meta: { name: 'æ¦è§', affix: true }
},
{
path: 'list',
component: () => import('@/views/myModule/list/index.vue'),
meta: { name: 'å表管ç' }
}
]
}
æ¥éª¤ 2: 注åè·¯ç±
å¨ src/router/routes/index.ts ä¸å¯¼å
¥å¹¶æ³¨åï¼
import { MyModuleOverview } from './myModule'
const myModuleMenu = {
path: 'myModule',
component: Layout,
meta: {
name: 'My Module',
icon: 'top-nav-icon',
globalKey: 'myModule',
globalModel: 'myModule'
},
children: [
MyModuleOverview
]
}
export const asyncRoutes = [
// ...
myModuleMenu
]
æ¥éª¤ 3: æ·»å æ¨¡å常é
å¨ src/router/constant.ts 䏿·»å æ¨¡åæ è¯ï¼
export enum PidValue {
// ...
MY_MODULE = 100 // æ°æ¨¡åID
}
export enum ModuleHomePath {
// ...
MY_MODULE = '/myModule' // 模åé¦é¡µè·¯å¾
}
2. å建 Vuex Store
Store ç»æ
// src/components/MyModule/store/index.ts
import { VuexModule } from '@/store'
import { IListParams, IListResult } from '@/types'
interface State {
list: any[]
detail: any
loading: boolean
}
const state: State = {
list: [],
detail: {},
loading: false
}
const actions = {
async fetchList ({ commit }, params: IListParams) {
commit('SET_LOADING', true)
try {
const res = await http.get('/api/my-module/list', { params })
commit('SET_LIST', res.data)
return res
} finally {
commit('SET_LOADING', false)
}
},
async fetchDetail ({ commit }, id: number) {
const res = await http.get(`/api/my-module/${id}`)
commit('SET_DETAIL', res.data)
return res
},
async addItem ({ commit }, data: any) {
return await http.post('/api/my-module', data)
},
async updateItem ({ commit }, { id, ...data }: any) {
return await http.put(`/api/my-module/${id}`, data)
},
async deleteItem ({ commit }, id: number) {
return await http.delete(`/api/my-module/${id}`)
}
}
const mutations = {
SET_LIST (state: State, list: any[]) {
state.list = list
},
SET_DETAIL (state: State, detail: any) {
state.detail = detail
},
SET_LOADING (state: State, loading: boolean) {
state.loading = loading
}
}
const store: VuexModule<State> = {
name: 'myModule',
namespaced: true,
state,
actions,
mutations
}
export default store
å建 AbsView åºç±»
// src/components/MyModule/AbsView/AbsMyModuleView.ts
import { Component, Vue } from 'vue-property-decorator'
import { namespace } from 'vuex-class'
import { StoreProvide } from '@/utils/decorators'
import store from '../store'
const $store = namespace('myModule')
@Component
@StoreProvide([store])
export default class AbsMyModuleView extends Vue {
@$store.Action('fetchList')
fetchList!: IGenericAction<IListParams, IListResult<any[]>>
@$store.Action('fetchDetail')
fetchDetail!: IGenericAction<{ id: number }, any>
@$store.Action('addItem')
addItem!: IGenericAction<any, boolean>
@$store.Action('updateItem')
updateItem!: IGenericAction<any, boolean>
@$store.Action('deleteItem')
deleteItem!: IGenericAction<{ id: number }, boolean>
}
3. å建 CRUD 页é¢
åè crud-pages æè½å建æ å CRUD 页é¢ï¼
<template>
<div class="main-wrapper">
<GridList
ref="list"
:show-pagination="true"
:store-load-list="fetchList"
:chain-query="chainQuery"
>
<!-- æç´¢è¡¨å -->
<template slot="form" slot-scope="{ $ctx, query }">
<el-form :inline="true" @submit.native.prevent>
<el-form-item class="master-btns">
<el-button
v-acl="`/myModule|${PERMISSION_FLAG.ADD}`"
type="primary"
@click="handleAdd"
>
æ°å¢
</el-button>
</el-form-item>
<el-form-item>
<Search
v-model.trim="query.searchValue"
:search-key="['åç§°']"
:on-search="() => $ctx.load({ pager: { page: 1 } })"
/>
</el-form-item>
</el-form>
</template>
<!-- è¡¨æ ¼ -->
<template slot="table" slot-scope="{ grid }">
<el-table :data="grid.list" stripe>
<el-table-column prop="name" label="åç§°" />
<el-table-column label="æä½" fixed="right" width="200" class-name="col-actions">
<template slot-scope="{ row }">
<el-button type="text" size="small" @click="handleEdit(row)">ç¼è¾</el-button>
<el-button type="text" size="small" @click="handleDelete(row)">å é¤</el-button>
</template>
</el-table-column>
</el-table>
</template>
</GridList>
<!-- å¯¹è¯æ¡ -->
<AbsFormDialog :entity.sync="formDlg" size="normal">
<template v-slot="{ model, rules }">
<el-form class="v-form" :model="model" :rules="rules">
<el-form-item prop="name" label="åç§°">
<el-input v-model.trim="model.name" class="v-form--ctl" />
</el-form-item>
</el-form>
</template>
</AbsFormDialog>
</div>
</template>
<script lang="ts">
import { Component } from 'vue-property-decorator'
import { GridList, AbsFormDialog, DialogModelService } from '@tdio/tdui'
import AbsMyModuleView from '@/components/MyModule/AbsView/AbsMyModuleView'
import { genRequired } from '@/utils/validator'
import { PERMISSION_FLAG } from '@/components/ACLs/model'
@Component({
components: {
GridList,
AbsFormDialog
},
data () {
return {
PERMISSION_FLAG
}
}
})
export default class MyModuleList extends AbsMyModuleView {
loadData (params?: Partial<IListParams>) {
(this.$refs.list as any).load(params)
}
chainQuery (query: IQuery) {
return query
}
handleAdd () {
this.formDlg.show({}, 'æ°å¢')
}
handleEdit (row: Kv) {
const { id } = row
this.fetchDetail({ id }).then(data => {
if (data) {
this.formDlg.show(data, 'ç¼è¾')
}
})
}
handleDelete (row: Kv) {
const { id } = row
this.$confirm('确认å é¤ï¼', 'æç¤º', {
confirmButtonText: 'ç¡®å®',
cancelButtonText: 'åæ¶',
type: 'warning'
}).then(async () => {
await this.deleteItem({ id })
this.$message.success($t('Action Success'))
this.loadData()
}).catch(() => {})
}
formDlg = new DialogModelService<MyModuleList, any>(
$this => ({
rules: {
name: [genRequired('请è¾å
¥åç§°')]
},
onSubmit () {
const { data } = this
if (data.id) {
return $this.updateItem(data).then(res => {
if (res) {
$this.$message.success($t('Action Success'))
$this.loadData()
this.hide()
}
})
} else {
return $this.addItem(data).then(res => {
if (res) {
$this.$message.success($t('Action Success'))
$this.loadData()
this.hide()
}
})
}
}
})
)
}
</script>
项ç®è§èæ£æ¥æ¸ å
å¨å¼åè¿ç¨ä¸ï¼ç¡®ä¿éµå¾ªä»¥ä¸è§èï¼
代ç è§è
- éµå¾ª TypeScript ç±»åå®ä¹è§è
- ä½¿ç¨ Vue ç»ä»¶å¼åè§è
- éµå¾ªä»£ç 飿 ¼è§è
- 使ç¨ç»ä¸çå½åè§è
Git æäº¤
- æäº¤ä¿¡æ¯éµå¾ª Git æäº¤è§è
- æäº¤ç±»åæ£ç¡®ï¼feat/fix/refactorçï¼
- æäº¤ä¿¡æ¯ä½¿ç¨ä¸æ
ä¸å¡å¼å
- CRUD 页é¢éµå¾ªæ 忍¡å¼
- æéæ§å¶æ£ç¡®å®ç°
- 表åéªè¯è§å宿´
- é误å¤çå®å
- å½é
åææ¬ä½¿ç¨
$t()
常è§ä¸å¡åºæ¯
åºæ¯ 1: æ°æ®ç®¡ç模å
- å建路ç±é ç½®
- å建 Vuex storeï¼å å«å表ã详æ ãå¢å æ¹æ¥ï¼
- å建 AbsView åºç±»
- å建å表页é¢ï¼ä½¿ç¨ GridListï¼
- å建表åå¯¹è¯æ¡ï¼ä½¿ç¨ DialogModelServiceï¼
- æ·»å æéæ§å¶
åºæ¯ 2: 工使µé ç½®
- å建路ç±åèå
- å建é 置页é¢
- å®ç°é ç½®ä¿åé»è¾
- æ·»å é ç½®éªè¯
åºæ¯ 3: æ°æ®å±ç¤ºé¡µé¢
- å建æ¦è§é¡µé¢
- 使ç¨å¾è¡¨ç»ä»¶å±ç¤ºæ°æ®
- å®ç°æ°æ®å·æ°é»è¾
åèèµæº
- Vue ç»ä»¶å¼åï¼åè
vue-developmentæè½ - TypeScript è§èï¼åè
typescript-standardsæè½ - CRUD 页é¢ï¼åè
crud-pagesæè½ - Git æäº¤ï¼åè
git-commitæè½ - 代ç 飿 ¼ï¼åè
code-styleæè½
详ç»å¼åæå请åè references/DEVELOPMENT_GUIDE.md