Skip to content

Commit 98d7e9e

Browse files
author
zhongchubing
committed
feat: 导航标签功能
1 parent 14a6b1a commit 98d7e9e

File tree

17 files changed

+250
-40
lines changed

17 files changed

+250
-40
lines changed

geekape-nav-admin/config/routes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
{name: '审核列表', icon: 'audit', path: '/nav/audit', component: './nav/Audit'},
1111
{name: '导航列表', icon: 'send', path: '/nav/list', component: './nav/List'},
1212
{name: '分类列表', icon: 'smile', path: '/nav/category', component: './nav/Category'},
13+
{name: '标签列表', icon: 'smile', path: '/nav/tag', component: './nav/Tag'},
1314

1415
{path: '/', redirect: '/nav/audit'},
1516
{component: './404'},

geekape-nav-admin/src/pages/nav/Audit/index.tsx

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,26 @@
11
import GeekProTable from "@/components/GeekProTable/GeekProTable";
22
import {API_NAV_AUDIT, API_NAV_LIST} from "@/services/api";
33
import {ProColumns} from "@ant-design/pro-table";
4-
import {Popconfirm} from "antd";
4+
import {Popconfirm, Tag, Space} from "antd";
55
import request from "@/utils/request";
66

7+
function RandomColorTag({ children }) {
8+
const colors = [
9+
'magenta',
10+
'red',
11+
'volcano',
12+
'orange',
13+
'gold',
14+
'lime',
15+
'green',
16+
'cyan',
17+
'blue',
18+
'geekblue',
19+
'purple',
20+
]
21+
return <Tag color={colors[Math.floor(Math.random() * colors.length)]}>{children}</Tag>
22+
}
23+
724
export default function NavAuditListPage() {
825
const columns: ProColumns[] = [
926
{
@@ -23,12 +40,21 @@ export default function NavAuditListPage() {
2340
search: false,
2441
width: 180,
2542
},
43+
{
44+
title: '网站标签',
45+
dataIndex: 'tags',
46+
search: false,
47+
width: 250,
48+
renderText: (text, record)=> (<Space>
49+
{record.tags.map(item=> <RandomColorTag>{item}</RandomColorTag>)}
50+
</Space>)
51+
},
2652

2753
{
2854
title: '网站描述',
2955
dataIndex: 'desc',
3056
search: false,
31-
width: 500,
57+
width: 300,
3258
},
3359
{
3460
title: '网站链接',
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import {
2+
ModalForm, ProFormSelect, ProFormText,
3+
} from "@ant-design/pro-form";
4+
import useProFormItem from "@/hooks/useProFormItem";
5+
import useGeekProForm from "@/components/GeekProForm/useGeekProForm";
6+
import {API_TAG} from "@/services/api";
7+
import request from "@/utils/request";
8+
9+
export default function TagForm(props: any) {
10+
const formProps = useGeekProForm({
11+
...props,
12+
onInitialValues(values: any): object {
13+
return values
14+
},
15+
})
16+
const nameProps = useProFormItem({
17+
name: 'name',
18+
label: '标签名',
19+
width: 'sm',
20+
required: true,
21+
})
22+
23+
async function onFinish(values: any) {
24+
const data = {
25+
id: props.isEdit ? props.selectedData?._id : undefined,
26+
...values,
27+
}
28+
await request({
29+
url: API_TAG,
30+
method: props.isEdit ? 'PUT' : 'POST',
31+
msg: props.isEdit ? '修改成功' : '添加成功',
32+
data
33+
})
34+
props.hide();
35+
props.tableRef.reload()
36+
}
37+
38+
return (
39+
<ModalForm {...props} {...formProps} onFinish={onFinish} width={350}>
40+
<ProFormText {...nameProps} />
41+
</ModalForm>
42+
)
43+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import {Button, Popconfirm} from "antd";
2+
import request from "@/utils/request";
3+
import {API_CATEGORY, API_CATEGORY_LIST, API_TAG_list} from "@/services/api";
4+
import GeekProTable from "@/components/GeekProTable/GeekProTable";
5+
import {ActionType, ProColumns} from "@ant-design/pro-table";
6+
import {PlusOutlined} from "@ant-design/icons";
7+
import useGeekProTablePopup from "@/components/GeekProTable/useGeekProTablePopup";
8+
import {useRef, useState} from "react";
9+
import TagForm from "@/pages/nav/Tag/form";
10+
11+
12+
export default function NavTagListPage() {
13+
const formProps = useGeekProTablePopup()
14+
const tableRef = useRef<ActionType>();
15+
const [tagList, setTagList] = useState([]);
16+
17+
async function onRequestData() {
18+
const { data } = await request({
19+
url: API_TAG_list,
20+
method: 'GET',
21+
data: {
22+
showInMenu: false
23+
}
24+
})
25+
setTagList(data.data)
26+
return data
27+
}
28+
29+
30+
async function onDelete(id: string, action: any) {
31+
await request({
32+
url: API_CATEGORY,
33+
method: 'DELETE',
34+
data: {
35+
id,
36+
},
37+
msg: '删除成功',
38+
})
39+
action.reload()
40+
}
41+
42+
const columns: ProColumns[] = [
43+
{
44+
title: '标签名',
45+
dataIndex: 'name'
46+
},
47+
]
48+
return (
49+
<div>
50+
<GeekProTable
51+
actionRef={tableRef}
52+
columns={columns}
53+
pageHeaderProps={{
54+
extra: <Button type='primary' onClick={()=> formProps.show()}><PlusOutlined />添加标签</Button>
55+
}}
56+
search={false}
57+
request={onRequestData}
58+
renderOptions={(text, record, _, action)=> ([
59+
<a onClick={()=> formProps.show({type: 'edit', data: record, action})}>编辑</a>,
60+
<Popconfirm title={'确定删除吗?'} onConfirm={() => onDelete(record._id, action)}>
61+
<a>删除</a>
62+
</Popconfirm>,
63+
])}
64+
/>
65+
<TagForm {...formProps} tableRef={tableRef.current} tagList={tagList} />
66+
</div>
67+
);
68+
}

geekape-nav-admin/src/services/api.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ export const API_NAV = '/api/nav'
66
export const API_NAV_AUDIT = '/api/nav/audit'
77
export const API_CATEGORY_LIST = '/api/category/list'
88
export const API_CATEGORY = '/api/category'
9+
export const API_TAG = '/api/tag'
10+
export const API_TAG_list = '/api/tag/list'
911

1012
export async function login(data: { username: string, password: string }) {
1113
return request({

geekape-nav-main/api/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export const API_NAV_REPTILE = '/api/nav/reptile'
1818
export const API_NAV_RANDOM = '/api/nav/random'
1919
export const API_NAV_FIND = '/api/nav/find'
2020
export const API_CATEGORY_LIST = '/api/category/list'
21+
export const API_TAG_LIST = '/api/tag/list'
2122

2223
const api = {
2324
addNav(data) {

geekape-nav-main/components/AddNavPopup.vue

Lines changed: 52 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,34 @@
77
width="320"
88
@close="$emit('update:show', false)"
99
>
10-
<el-form ref="ruleForm" label-width="100px" :model="form" :rules="rules">
10+
<el-form ref="ruleForm" label-width="100px" :model="form" :rules="rules" v-loading="formLoading">
1111

1212
<el-form-item label="网站链接" prop="url">
1313
<el-input placeholder="http://www.baidu.com/" v-model="form.href" :disabled="type === 'update'" @blur="getNavInfo" />
1414
<span style="color: red">输入链接自动爬取信息</span>
1515
</el-form-item>
1616

17-
<el-form-item label="网站分类" prop="categoryId">
18-
<el-select v-model="form.categoryId" placeholder="请选择" filterable>
19-
<el-option-group
20-
v-for="group in categorys"
21-
:key="group._id"
22-
:label="group.name"
23-
>
24-
<el-option
25-
v-for="item in group.children"
26-
:key="item._id"
27-
:label="item.name"
28-
:value="item._id"
29-
></el-option>
30-
</el-option-group>
17+
<el-form-item label="网站标签" prop="tags">
18+
<el-select
19+
v-model="form.tags"
20+
multiple
21+
:multiple-limit="5"
22+
filterable
23+
allow-create
24+
default-first-option
25+
placeholder="输入网站标签,最多5个">
26+
<el-option
27+
v-for="item in tags"
28+
:key="item.value"
29+
:label="item.label"
30+
:value="item.value">
31+
</el-option>
3132
</el-select>
3233
</el-form-item>
3334
<el-form-item label="网站名称" prop="name">
3435
<el-input placeholder="输入网站名称" v-model="form.name" />
3536
</el-form-item>
37+
3638
<el-form-item label="网站logo" prop="name">
3739
<el-input placeholder="输入网站logo" v-model="form.logo" />
3840
<img style="max-width: 30px;" :src="form.logo" />
@@ -58,7 +60,7 @@
5860

5961
<script>
6062
import axios from "../plugins/axios";
61-
import {API_NAV, API_NAV_RANDOM, API_NAV_REPTILE} from "../api";
63+
import {API_NAV, API_NAV_RANDOM, API_NAV_REPTILE, API_TAG_LIST} from "../api";
6264
6365
export default {
6466
props: {
@@ -77,11 +79,14 @@ export default {
7779
data() {
7880
return {
7981
loading: false,
82+
formLoading: false,
8083
categorys: [],
84+
tags: [],
8185
form: {
8286
href: '',
8387
categoryId: '',
8488
name: '',
89+
tags: [],
8590
logo: '',
8691
desc: '',
8792
authorName: '',
@@ -95,8 +100,8 @@ export default {
95100
message: '请输入正确的url',
96101
},
97102
],
98-
categoryId: [
99-
{ required: true, message: '请选择分类', trigger: 'blur' },
103+
tags: [
104+
{ required: true, message: '请输入标签', trigger: 'blur' },
100105
],
101106
name: [{ required: true, message: '请输入名称', trigger: 'blur' },],
102107
desc: [{ required: true, message: '请输入描述', trigger: 'blur' },],
@@ -120,6 +125,18 @@ export default {
120125
}
121126
},
122127
methods: {
128+
async getTags() {
129+
const res = await axios.get(API_TAG_LIST)
130+
if (res.code === 1) {
131+
let data = res.data?.data
132+
data = data.map(item=> {
133+
item.value = item.name
134+
item.label = item.name
135+
return item
136+
})
137+
this.tags = res.data?.data
138+
}
139+
},
123140
async getCategorys() {
124141
const { data } = await this.$api.getCategoryList()
125142
this.categorys = data
@@ -129,19 +146,12 @@ export default {
129146
if (valid) {
130147
this.loading = true
131148
// 判断编辑还是更新
132-
if (this.type === 'update') {
133-
const id = this.item._id
134-
const res = await this.$api.editNav({
135-
id,
136-
...this.form
137-
})
149+
150+
const res = await this.$api.addNav(this.form)
151+
if (res.code === 0) {
152+
this.$message.error(`${res.msg}`)
138153
} else {
139-
const res = await this.$api.addNav(this.form)
140-
if (res.code === 0) {
141-
this.$message.error(`${res.msg}`)
142-
} else {
143-
this.$message(`感谢您的提交,请等待后台审核通过!`)
144-
}
154+
this.$message(`感谢您的提交,请等待后台审核通过!`)
145155
}
146156
this.loading = false
147157
this.$emit('update:show', false)
@@ -154,15 +164,21 @@ export default {
154164
async getNavInfo() {
155165
const { href: url } = this.form
156166
if (!url) return
157-
const { data } = await axios.get(API_NAV_REPTILE + `?url=${url}`)
158-
159-
this.form.logo = `https://www.google.com/s2/favicons?domain=${url}`
160-
this.form.name = data?.name
161-
this.form.desc = data?.desc
167+
this.formLoading = true
168+
try {
169+
const { data } = await axios.get(API_NAV_REPTILE + `?url=${url}`)
170+
this.form.logo = `https://www.google.com/s2/favicons?domain=${url}`
171+
this.form.name = data?.name
172+
this.form.desc = data?.desc
173+
} catch (e) {
174+
message.error('请求超时')
175+
this.$emit('update:show', false)
176+
}
177+
this.formLoading = false
162178
}
163179
},
164180
created() {
165-
this.getCategorys()
181+
this.getTags()
166182
},
167183
}
168184
</script>

geekape-nav-main/plugins/axios.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,6 @@ myAxios.interceptors.response.use(function (response) {
4242
return Promise.reject(error.response.data.message);
4343
});
4444

45+
myAxios.defaults.timeout = 6000
46+
4547
export default myAxios

geekape-nav-server/app/controller/nav.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,18 @@ export default class NavController extends Controller {
8585
}
8686

8787
async audit() {
88+
const { ctx } = this
8889
this.ctx.request.body.auditTime = new Date()
90+
91+
const { status, id } = this.ctx.request.body
92+
93+
const navItem = await this.ctx.model.Nav.findOne({ _id: id })
94+
const { tags } = navItem
95+
96+
if (status === NAV_STATUS.pass) {
97+
// 批量添加tag
98+
await this.ctx.service.tag.addMultiTag(tags)
99+
}
89100
await super.update();
90101
}
91102

geekape-nav-server/app/controller/tag.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,8 @@ export default class CategoryController extends Controller {
44
tableName(): string {
55
return 'Tag';
66
}
7+
8+
async getList() {
9+
await super.getList()
10+
}
711
}

geekape-nav-server/app/core/base_controller.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ export default class CommonController extends Controller {
7575
async getList(findObj = {}, otherCMD = (_table: any) => _table) {
7676
const { request, query } = this.ctx
7777
const tableName = this.tableName()
78+
7879
try {
7980
let { pageSize = 10, pageNumber = 1 } = query
8081
pageSize = Number(pageSize)

geekape-nav-server/app/model/nav.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ module.exports = app => {
1313
authorUrl: String,
1414
auditTime: Date,
1515
createTime: Date,
16+
tags: {
17+
type: Array,
18+
default: []
19+
},
1620
view: {
1721
type: Number,
1822
default: 0,

0 commit comments

Comments
 (0)