角色管理屬于權(quán)限管理的一個(gè)部分缀壤,可以預(yù)設(shè)一些角色比如課程管理員病袄,廣告管理員,超級(jí)管理員歉甚,普通用戶等等万细,然后在實(shí)際使用時(shí)分配給不同不同的用戶不同的角色,便于操作(不需要給某個(gè)用戶進(jìn)行詳細(xì)的功能設(shè)置)
我們涉及到的功能有:
- 制作添加角色铃芦,編輯角色雅镊,分配菜單
- 布局,列表展示刃滓,刪除功能仁烹,分配資源
基礎(chǔ)準(zhǔn)備工作:
views/role
.
├── components
│ └── list.vue 角色列表組件
└── index.vue 角色組件
角色頁(yè)面初始化代碼:
<template>
<div class="role">
<role-list></role-list>
</div>
</template>
<script>
import RoleList from './components/list'
export default {
name: 'RoleIndex',
components: {
RoleList
}
}
</script>
<style lang="scss" scoped></style>
角色列表組件初始化代碼(實(shí)現(xiàn)展示和刪除功能)因?yàn)檎故竞蛣h除我們已經(jīng)做了很多次了這里就不再贅述
<template>
<div class="role-list">
<el-card class="box-card">
<div slot="header" class="clearfix">
<el-form ref="form" :model="form">
<el-form-item label="角色名稱">
<el-input v-model="form.name"></el-input>
</el-form-item>
<el-form-item>
<el-button
type="primary"
@click="onSubmit"
v-loading:="isLoading"
>查詢</el-button>
<el-button @click="onReset">重置</el-button>
</el-form-item>
</el-form>
</div>
<el-button>添加角色</el-button>
<el-table
v-loading="isLoading"
:data="roles"
style="width: 100%">
<el-table-column
prop="id"
label="編號(hào)"
>
</el-table-column>
<el-table-column
prop="name"
label="角色名稱"
/>
<el-table-column
prop="description"
label="描述"
/>
<el-table-column
prop="createdTime"
label="添加時(shí)間"
>
<template slot-scope="scope">
<span>{{ scope.row.createdTime | dateFormat }}</span>
</template>
</el-table-column>
<el-table-column
align="center"
label="操作"
width="150px"
>
<template slot-scope="scope">
<div>
<el-button
type="text"
>分配菜單</el-button>
<el-button
type="text"
>分配資源</el-button>
</div>
<div>
<el-button
type="text"
@click="handleEdit(scope.row)"
>編輯</el-button>
<el-button
type="text"
@click="handleDelete(scope.row)"
>刪除</el-button>
</div>
</template>
</el-table-column>
</el-table>
</el-card>
</div>
</template>
<script>
// 引入請(qǐng)求方法
import { getRoles, deleteRole } from '@/services/role'
// 因?yàn)椴恢挂粋€(gè)地方使用了fliter時(shí)間日期過(guò)濾器了,所以我們封裝這個(gè)功能咧虎,再?gòu)墓ぞ哳愔幸?import dateFormat from '@/utils/dateformat'
export default {
name: 'RoleList',
data () {
return {
form: {
name: ''
},
isLoading: false,
roles: []
}
},
created () {
this.loadRoles()
},
methods: {
onSubmit () {
},
onReset () {
},
handleEdit (role) {
},
handleDelete (role) {
// 刪除角色
this.$confirm(`確認(rèn)刪除角色:${role.name}卓缰?`, '刪除提示')
.then(async () => {
await deleteRole(role.id)
this.$message.success('刪除成功')
this.loadRoles()
})
.catch(err => {
if (err && err.response) {
this.$message.error('刪除失敗,請(qǐng)重試')
} else {
this.$message.info('取消刪除')
}
})
},
async loadRoles () {
this.isLoading = true
const { data } = await getRoles(this.form)
this.roles = data.data.records
this.isLoading = false
}
},
filters: {
dateFormat
}
}
</script>
<style lang="scss" scoped>
</style>
創(chuàng)建services/role.js角色接口操作模塊
import request from '@/utils/request'
// 獲取角色
export const getRoles = data => {
return request({
method: 'POST',
url: '/boss/role/getRolePages',
data
})
}
// 刪除角色
export const deleteRole = id => {
return request({
method: 'DELETE',
url: `/boss/role/${id}`
})
}
再三強(qiáng)調(diào)砰诵,再三強(qiáng)調(diào)征唬,要核實(shí)英語(yǔ)單詞拼寫(本人這里又因?yàn)閱卧~問(wèn)題浪費(fèi)了很多時(shí)間來(lái)調(diào)試)
準(zhǔn)備工作到此結(jié)束
添加角色布局
使用Element的Dialog對(duì)話框組件
// Element 官方示例:Dialog 對(duì)話框組件
<el-dialog
title="提示"
:visible.sync="dialogVisible"
width="30%"
:before-close="handleClose">
<span>這是一段信息</span>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click="dialogVisible = false">確 定</el-button>
</span>
</el-dialog>
<script>
export default {
data() {
return {
dialogVisible: false
};
},
methods: {
handleClose(done) {
this.$confirm('確認(rèn)關(guān)閉?')
.then(_ => {
done();
})
.catch(_ => {});
}
}
};
</script>
添加到頁(yè)面中最后位置茁彭,不需要關(guān)閉處理总寒,刪除就可以了
- 點(diǎn)擊頂部添加按鈕時(shí),將dialogVisible設(shè)置為true理肺,讓對(duì)話框顯示
// role/components/list.vue
<template>
<div class="role-list">
<el-card class="box-card">
...
<!-- 點(diǎn)擊添加按鈕摄闸,顯示對(duì)話框 -->
<el-button @click="dialogVisible = true" >添加角色</el-button>
...
</el-card>
<!-- 對(duì)話框組件:刪除 :before-close="handleClose" -->
<el-dialog
title="添加角色"
:visible.sync="dialogVisible"
width="30%"
>
<span>這是一段信息</span>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click="dialogVisible = false">確 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
export default {
data() {
return {
...
dialogVisible: false
};
}
};
</script>
內(nèi)部的form表單結(jié)構(gòu)不建議直接書(shū)寫,因?yàn)椴恢挂粋€(gè)功能使用這個(gè)結(jié)構(gòu)妹萨,建議單獨(dú)封裝一個(gè)組件進(jìn)行處理
// role/components/create-or-edit.vue
<template>
<div>
<el-form>
<el-form-item label="角色名稱">
<el-input></el-input>
</el-form-item>
<el-form-item label="角色編碼">
<el-input></el-input>
</el-form-item>
<el-form-item label="角色描述">
<el-input type="textarea"></el-input>
</el-form-item>
<el-form-item>
<el-button>取消</el-button>
<el-button type="primary">確認(rèn)</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
name: 'CreateOrEdit'
}
</script>
<style lang="scss" scoped></style>
引入到list組件中年枕,并將其注冊(cè)為子組件
// role/components/list.vue
<el-dialog
title="添加角色"
:visible.sync="dialogVisible"
width="30%">
<!-- 將對(duì)話框內(nèi)容更換為自定義組件 -->
<create-or-edit></create-or-edit>
</el-dialog>
...
<script>
...
import CreateOrEdit from './create-or-edit'
export default {
...
components: {
CreateOrEdit
},
...
}
</script>
結(jié)構(gòu)準(zhǔn)備完畢,設(shè)置請(qǐng)求乎完,提交表單用
// services/role.js
...
// 添加或編輯角色
export const createOrUpdate = data => {
return request({
method: 'POST',
url: '/boss/role/saveOrUpdate',
data
})
}
引入文件熏兄,根據(jù)接口要求聲明綁定數(shù)據(jù),綁定給元素,瀏覽器可以查看效果
// create-or-edit.vue
<el-form>
<el-form-item label="角色名稱">
<el-input v-model="role.name"></el-input>
</el-form-item>
<el-form-item label="角色編碼">
<el-input v-model="role.code"></el-input>
</el-form-item>
<el-form-item label="角色描述">
<el-input v-model="role.description" type="textarea"></el-input>
</el-form-item>
<el-form-item>
<el-button>取消</el-button>
<el-button type="primary">確認(rèn)</el-button>
</el-form-item>
</el-form>
<script>
import { createOrEdit } from "@/services/role"
export default {
name: 'CreateOrEdit',
data () {
return {
// 根據(jù)接口要求綁定數(shù)據(jù)
role: {
code: '',
name: '',
description: ''
}
}
}
}
</script>
點(diǎn)擊確認(rèn)摩桶,提交表單
// create-or-edit.vue
<el-button type="primary" @click="onSubmit">確認(rèn)</el-button>
...
<script>
...
methods: {
async onSubmit () {
// 省略驗(yàn)證步驟
const { data } = await createOrEdit(this.role)
if (data.code === '000000') {
}
}
}
...
</script>
成功之后呢桥状,應(yīng)該關(guān)閉對(duì)話框并且刷新列表,這些都是list.vue的功能典格,這個(gè)需要用一個(gè)子傳父的通信功能了
- 給子組件注冊(cè)自定義事件
- 父組件監(jiān)聽(tīng)事件岛宦,觸發(fā)就說(shuō)明添加成功,就可以進(jìn)行下一步的處理了
// create-or-edit.vue
...
async onSubmit () {
const { data } = await createOrEdit(this.role)
if (data.code === '000000') {
// 提示
this.$message.success('添加成功')
// 子組件觸發(fā)自定義事件
this.$emit('success')
// 清空內(nèi)容
this.role = {}
}
}
...
// list.vue
<create-or-edit
@success="onSuccess"
></create-or-edit>
...
<script>
...
// 添加成功的操作
onSuccess () {
// 關(guān)閉對(duì)話框
this.dialogVisible = false
// 刷新列表數(shù)據(jù)
this.loadRoles()
},
...
</script>
當(dāng)然了耍缴,取消按鈕也是需要設(shè)置的,點(diǎn)擊取消挽霉,關(guān)閉對(duì)話框防嗡,同樣的需要子傳父
// create-or-edit.vue
<el-button
@click="onCancel"
>取消</el-button>
...
<script>
...
onCancel () {
this.$emit('cancel')
this.role = {}
}
...
</script>
由于取消無(wú)需刷新列表,可以直接在行內(nèi)標(biāo)簽寫入我們所需的關(guān)閉彈窗
// list.vue
<create-or-edit
...
@cancel="dialogVisible = false"
></create-or-edit>
編輯角色
編輯功能和添加功能類似侠坎,采用同一組件蚁趁,操作時(shí)使用isEdit傳遞狀態(tài)
// list.vue
<script>
...
data () {
return {
...
// 添加或編輯
isEdit: false,
...
}
},
...
</script>
...
<el-dialog
:title="isEdit ? '編輯角色' : '添加角色'"
...>
<!-- 將對(duì)話框內(nèi)容更換為自定義組件 -->
<create-or-edit
:is-edit="isEdit"
...
></create-or-edit>
</el-dialog>
子組件接收狀態(tài)
// create-or-edit.vue
props: {
isEdit: {
type: Boolean,
default: false
}
},
點(diǎn)擊添加時(shí),設(shè)置isEdit為false
// list.vue
<el-button @click="handleAdd" >添加角色</el-button>
...
<script>
...
handleAdd () {
this.dialogVisible = true
this.isEdit = false
},
...
</script>
點(diǎn)擊編輯按鈕实胸,設(shè)置isEdit為true他嫡,同時(shí)彈出對(duì)話框
// list.vue
...
handleEdit (role) {
// 顯示對(duì)話框
this.dialogVisible = true
// 設(shè)置編輯狀態(tài)
this.isEdit = true
},
點(diǎn)擊編輯時(shí)將數(shù)據(jù)綁定給表單,需要父?jìng)髯訉⒕庉嫷慕巧玦d傳入
- 傳入id由子組件重新查詢庐完,可以確保數(shù)據(jù)為最新的數(shù)據(jù)钢属,避免數(shù)據(jù)不齊全的情況
// list.vue
<script>
...
data () {
...
// 正在編輯的角色I(xiàn)D
roleId: null
}
},
handleEdit (role) {
this.dialogVisible = true
this.isEdit = true
// 將要編輯的角色 ID 傳遞給表單展示
this.roleId = role.id
},
...
</script>
...
<create-or-edit
:is-edit="isEdit"
:role-id="roleId"
@success="onSuccess"
@cancel="dialogVisible = false"
></create-or-edit>
子組件接收,并且在created鉤子函數(shù)下展示
// create-or-list.vue
props: {
...
roleId: {
type: Object
}
},
created () {
if (this.isEdit) {
console.log(roleId)
}
},
封裝請(qǐng)求功能
// services/role.js
...
// 獲取角色
export const getRoleById = id => {
return request({
method: 'GET',
url: `/boss/role/${id}`,
})
}
引入請(qǐng)求角色數(shù)據(jù)
// create-or-edit.vue
created () {
if (this.isEdit) {
// 加載用戶數(shù)據(jù)
this.loadRole()
}
},
...
async loadRole () {
const { data } = await getRoleById(this.roleId)
if (data.code === '000000') {
// 將角色數(shù)據(jù)更新給 role 即可
this.role = data.data
}
},
提交功能因?yàn)槲覀兊慕涌谑切略龊途庉嫷膮^(qū)別在于id门躯,role中自動(dòng)包含了參數(shù)id淆党,所以無(wú)需修改直接提交
優(yōu)化:role數(shù)據(jù)渲染問(wèn)題
以上的方法是本人自行解決的辦法,但是有更好的做法:
由于當(dāng)前組件只是顯示和隱藏譬挚,組件沒(méi)有銷毀和創(chuàng)建锅铅,所以我們通過(guò)v-if來(lái)控制對(duì)話框,達(dá)到生命周期函數(shù)created重新運(yùn)行的目的,可以避免數(shù)據(jù)只會(huì)渲染一次的錯(cuò)誤
// list.vue
<create-or-edit
v-if="dialogVisible"
...
></create-or-edit>
完成
分配菜單
分配菜單用于設(shè)置角色可以訪問(wèn)哪些菜單功能
布局與路由處理
創(chuàng)建文件
// role/alloc-menu.vue
<template>
<div class="alloc-menu"></div>
</template>
<script>
export default {
name: 'AllocMenu'
}
</script>
<style lang="scss" scoped></style>
添加路由减宣,設(shè)置動(dòng)態(tài)參數(shù)
// router/index.js
...
{
path: '/role/:roleId/alloc-menu',
name: 'alloc-menu',
component: () => import(/* webpackChunkName: 'alloc-menu' */'@/views/role/alloc-menu')
}
]
...
點(diǎn)擊分配菜單按鈕盐须,進(jìn)行導(dǎo)航跳轉(zhuǎn)
- 跳轉(zhuǎn)后,可以通過(guò)$route來(lái)獲取要分配菜單的用戶id
// list.vue
<!-- scope.row 為作用域插槽提供的當(dāng)前行數(shù)據(jù) -->
<el-button
type="text"
@click="$router.push({
name: 'alloc-menu',
params: {
roleId: scope.row.id
}
})"
>分配菜單</el-button>
使用這種方式非常簡(jiǎn)單漆腌,但是會(huì)讓組件與路由耦合(組件無(wú)法獨(dú)立于路由使用)
- 如果希望組件與路由解耦贼邓,可以將動(dòng)態(tài)路由參數(shù)替換為props(這個(gè)方法可以詳細(xì)參考一下Vue Router階段->路由傳參處理)
// router/index.js
// - 設(shè)置 props: true阶冈,讓路徑參數(shù)通過(guò) props 方式傳遞給組件
{
path: '/role/:roleId/alloc-menu',
name: 'alloc-menu',
component: () => import(/* webpackChunkName: 'alloc-menu' */'@/views/role/alloc-menu'),
props: true
},
// alloc-menu.vue
props: {
// 組件內(nèi)需要通過(guò) props 接收路徑傳遞的參數(shù),實(shí)現(xiàn)解耦
// - 注意塑径,$route 里的數(shù)據(jù)雖然還能訪問(wèn)女坑,但不要用,否則組件與路由還是耦合统舀,解耦就白寫了
roleId: {
type: [String, Number],
required: true
}
}
菜單列表展示
這里使用Element的Tree樹(shù)形控件組件
// Element 官方示例:Tree 樹(shù)形控件基礎(chǔ)用法
<el-tree :data="data" :props="defaultProps" @node-click="handleNodeClick"></el-tree>
<script>
export default {
data() {
return {
data: [{
label: '一級(jí) 1',
children: [{
label: '二級(jí) 1-1',
children: [{
label: '三級(jí) 1-1-1'
}]
}]
}, {
label: '一級(jí) 2',
children: [{
label: '二級(jí) 2-1',
children: [{
label: '三級(jí) 2-1-1'
}]
}, {
label: '二級(jí) 2-2',
children: [{
label: '三級(jí) 2-2-1'
}]
}]
}, {
label: '一級(jí) 3',
children: [{
label: '二級(jí) 3-1',
children: [{
label: '三級(jí) 3-1-1'
}]
}, {
label: '二級(jí) 3-2',
children: [{
label: '三級(jí) 3-2-1'
}]
}]
}],
defaultProps: {
children: 'children',
label: 'label'
}
};
},
methods: {
handleNodeClick(data) {
console.log(data);
}
}
};
</script>
引入到頁(yè)面中匆骗,去除事件
- 設(shè)置一個(gè)Card作為容器
- 設(shè)置默認(rèn)全部展開(kāi),使用
<el-tree>
組件的
dafault-expand-all屬性 - 設(shè)置復(fù)選框提示誉简,使用show-checkbox屬性
- data代表的是樹(shù)形圖數(shù)據(jù)碉就,更改為menus避免混淆
- defaultProps代表讀取數(shù)據(jù)時(shí),屬性對(duì)應(yīng)的功能闷串,因?yàn)檎?qǐng)求接口時(shí)瓮钥,不是所有的接口都用label作為標(biāo)題,具體根據(jù)接口返回的數(shù)據(jù)為標(biāo)準(zhǔn)
- 請(qǐng)求數(shù)據(jù)接口:接口地址
- 將其封裝到services/menu.js中
// services/menu.js
...
// 獲取所有菜單并按層級(jí)展示(注意烹吵,這是菜單功能碉熄,保存到 menu.js 中)
export const getMenuNodeList = () => {
return request({
method: 'GET',
url: '/boss/menu/getMenuNodeList'
})
}
- 引入請(qǐng)求數(shù)據(jù),由于對(duì)應(yīng)標(biāo)題和層級(jí)的屬性與默認(rèn)名稱不同肋拔,需要進(jìn)行設(shè)置锈津,menus中的默認(rèn)數(shù)據(jù)也可以刪掉
<template>
<div class="alloc-menu">
<el-card>
<el-tree
:data="menus"
:props="defaultProps"
show-checkbox
default-expand-all
>
</el-tree>
</el-card>
</div>
</template>
<script>
import { getMenuNodeList } from '@/services/menu'
export default {
name: 'AllocMenu',
props: {
roleId: {
type: [Number, String],
required: true
}
},
created () {
this.loadMenus()
},
data () {
return {
menus: [],
defaultProps: {
children: 'subMenuList',
label: 'name'
}
}
},
methods: {
async loadMenus () {
const { data } = await getMenuNodeList()
if (data.code === '000000') {
this.menus = data.data
}
}
}
}
</script>
<style lang="scss" scoped>
</style>
保存與清空
設(shè)置按鈕結(jié)構(gòu)
// alloc-menu.vue
<el-card>
<el-tree
...
></el-tree>
<div style="margin: 20px;">
<el-button>清空</el-button>
<el-button type="primary">保存</el-button>
</div>
</el-card>
保存
- 觀察接口,需要用戶id與菜單列表(參數(shù)有點(diǎn)復(fù)雜)
// services/menu.js
...
// 給角色分配菜單
export const allocateRoleMenus = data => {
return request({
method: 'POST',
url: '/boss/menu/allocateRoleMenus',
data
})
}
引入并且在調(diào)用保存按鈕時(shí)調(diào)用
- 請(qǐng)求參數(shù)需要分配的菜單列表(由勾選選項(xiàng)組成)只损,可以通過(guò)tree組件的getCheckedKeys方法來(lái)獲取
- 首先要給tree組件設(shè)置一個(gè)ref一姿,才能找到指定的tree組件
- 如果通過(guò)getCheckedKeys方法獲取,需要給tree組件設(shè)置一個(gè)node-key來(lái)設(shè)置通過(guò)哪個(gè)屬性作為唯一標(biāo)識(shí)(比如id)
- 提交成功跃惫,跳轉(zhuǎn)加提示信息
// alloc-menu.vue
...
<el-tree
ref="menu-tree"
node-key="id"
...
></el-tree>
...
<el-button type="primary" @click="onSave">保存</el-button>
...
<script>
import { getMenuNodeList, allocateRoleMenus } from '@/services/menu'
...
async onSave () {
// 傳入通過(guò)路徑參數(shù)接收的角色I(xiàn)D
const { data } = await allocateRoleMenus({
roleId: this.roleId,
menuIdList: this.$refs['menu-tree'].getCheckedKeys()
})
if (data.code === '000000') {
// 提示
this.$message.success('分配菜單成功')
// 返回角色列表頁(yè)即可
this.$router.push('/role')
}
}
改進(jìn)(勾選已分配選項(xiàng))
Tree組件具有default-checked-keys屬性叮叹,值為數(shù)組,當(dāng)node-key為id時(shí)爆存,數(shù)組內(nèi)存放的id對(duì)應(yīng)的選項(xiàng)會(huì)被選擇
通過(guò)接口來(lái)請(qǐng)求當(dāng)前角色擁有的菜單列表蛉顽,接口地址
// services/menu.js
...
// 獲取角色擁有的菜單列表
export const getRoleMenus = roleId => {
return request({
method: 'GET',
// 下面兩種方式均可
// url: `/boss/menu/getRoleMenus?roleId=${roleId}`,
url: '/boss/menu/getRoleMenus',
params: { // axios 會(huì)把 params 轉(zhuǎn)換為 urlencoded 并以 ? 連接到 url 后
roleId
}
})
}
引入并調(diào)用
// alloc-menu.vue
..
import { getMenuNodeList, allocateRoleMenus, getRoleMenus } from '@/services/menu'
...
created () {
...
// 加載角色擁有的菜單列表
this.loadRoleMenus()
},
...
async loadRoleMenus () {
// 請(qǐng)求角色擁有的菜單列表
const { data } = await getRoleMenus(this.roleId)
if (data.code === '000000') {
console.log(data)
}
},
觀察響應(yīng)數(shù)據(jù)可以發(fā)現(xiàn)一點(diǎn):每一個(gè)菜單項(xiàng)都有selected屬性,以此來(lái)判斷是否選中了數(shù)據(jù)先较,拿到了這些數(shù)據(jù)的id之后携冤,設(shè)置給default-checked-keys就可以了
data () {
return {
checkedKeys: []
}
}
...
methods: {
// 封裝的用于數(shù)據(jù)篩選的方法(篩選出被選中選項(xiàng)的菜單項(xiàng)的id)
getCheckedKeys (menus) {
// 遍歷數(shù)據(jù)(將所有存在子節(jié)點(diǎn)的node排除,對(duì)子節(jié)點(diǎn)列表進(jìn)行遍歷)
menus.forEach(menu => {
// 未選中闲勺,結(jié)束
if (!menu.selected) {
return
}
// 是否存在子節(jié)點(diǎn)
if (menu.subMenuList) {
return this.getCheckedKeys(menu.subMenuList)
}
// 選中的葉子節(jié)點(diǎn)曾棕,沒(méi)有子節(jié)點(diǎn)的節(jié)點(diǎn),存儲(chǔ)Id即可
// this.checkedKeys.push(menu.id)菜循,采用賦值的方法可以避免因?yàn)轭l繁的異步操作導(dǎo)致視圖不更新的問(wèn)題
this.checkedKeys = [...this.checkedKeys, menu.id]
})
},
async loadRoleMenus () {
const { data } = await getRoleMenus(this.roleId)
if (data.code === '000000') {
this.getCheckedKeys(data.data)
}
},
...
}
清空
Element-Tree-樹(shù)型節(jié)點(diǎn)的選擇實(shí)例演示了如何進(jìn)行清空
- 通過(guò)this.$refs.tree.setCheckedKeys([])即可清空
// alloc-menu.vue
<el-button @click="resetChecked">清空</el-button>
...
// 設(shè)置清空方法
resetChecked () {
this.$refs['menu-tree'].setCheckedKeys([])
}
完成翘地,旁邊的按鈕,分配資源以及查詢重置都是重復(fù)的內(nèi)容,可以快速完成