artalk 2.3.4 → 2.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/dist/Artalk.css +1 -1
  2. package/dist/Artalk.es.js +3171 -3008
  3. package/dist/Artalk.iife.js +1 -1
  4. package/dist/Artalk.js +1 -1
  5. package/dist/ArtalkLite.css +1 -1
  6. package/dist/ArtalkLite.es.js +3124 -2980
  7. package/dist/ArtalkLite.iife.js +1 -1
  8. package/dist/ArtalkLite.js +1 -1
  9. package/dist/src/api/admin.d.ts +10 -0
  10. package/dist/src/api/api-base.d.ts +14 -0
  11. package/dist/src/api/captcha.d.ts +14 -0
  12. package/dist/src/api/comment.d.ts +29 -0
  13. package/dist/src/api/index.d.ts +31 -0
  14. package/dist/src/api/page.d.ts +22 -0
  15. package/dist/src/api/request.d.ts +12 -0
  16. package/dist/src/api/site.d.ts +17 -0
  17. package/dist/src/api/system.d.ts +13 -0
  18. package/dist/src/api/upload.d.ts +11 -0
  19. package/dist/src/api/user.d.ts +28 -0
  20. package/dist/src/artalk.d.ts +58 -0
  21. package/dist/src/comment/actions.d.ts +17 -0
  22. package/dist/src/comment/comment.d.ts +67 -0
  23. package/dist/src/comment/index.d.ts +2 -0
  24. package/dist/src/comment/render.d.ts +76 -0
  25. package/dist/src/components/action-btn.d.ts +52 -0
  26. package/dist/src/components/dialog.d.ts +18 -0
  27. package/dist/src/components/pagination.d.ts +30 -0
  28. package/dist/src/components/read-more-btn.d.ts +33 -0
  29. package/dist/src/context.d.ts +72 -0
  30. package/dist/src/defaults.d.ts +3 -0
  31. package/dist/src/editor/editor.d.ts +84 -0
  32. package/dist/src/editor/index.d.ts +2 -0
  33. package/dist/src/editor/plugs/editor-plug.d.ts +26 -0
  34. package/dist/src/editor/plugs/emoticons-plug.d.ts +36 -0
  35. package/dist/src/editor/plugs/header-input-plug.d.ts +13 -0
  36. package/dist/src/editor/plugs/preview-plug.d.ts +10 -0
  37. package/dist/src/editor/plugs/upload-plug.d.ts +10 -0
  38. package/dist/src/i18n/en.d.ts +69 -0
  39. package/dist/src/i18n/index.d.ts +294 -0
  40. package/dist/src/i18n/zh-CN.d.ts +3 -0
  41. package/dist/src/layer/index.d.ts +3 -0
  42. package/dist/src/layer/layer.d.ts +32 -0
  43. package/dist/src/layer/sidebar-layer.d.ts +20 -0
  44. package/dist/src/lib/checker/admin-checker.d.ts +3 -0
  45. package/dist/src/lib/checker/captcha-checker.d.ts +3 -0
  46. package/dist/src/lib/checker/index.d.ts +42 -0
  47. package/dist/src/lib/component.d.ts +12 -0
  48. package/dist/src/lib/detect.d.ts +10 -0
  49. package/dist/src/lib/stat.d.ts +15 -0
  50. package/dist/src/lib/ui.d.ts +23 -0
  51. package/dist/src/lib/user.d.ts +13 -0
  52. package/dist/src/lib/utils.d.ts +39 -0
  53. package/dist/src/list/index.d.ts +2 -0
  54. package/dist/src/list/list-lite.d.ts +63 -0
  55. package/dist/src/list/list-nest.d.ts +10 -0
  56. package/dist/src/list/list.d.ts +26 -0
  57. package/dist/src/main.d.ts +2 -0
  58. package/dist/types/artalk-config.d.ts +132 -0
  59. package/dist/types/artalk-data.d.ts +204 -0
  60. package/dist/types/context.d.ts +146 -0
  61. package/dist/types/event.d.ts +28 -0
  62. package/dist/types/global.d.ts +0 -0
  63. package/dist/types/plug.d.ts +4 -0
  64. package/index.html +3 -3
  65. package/package.json +5 -5
  66. package/src/api/admin.ts +18 -0
  67. package/src/api/api-base.ts +27 -0
  68. package/src/api/captcha.ts +24 -0
  69. package/src/api/comment.ts +84 -0
  70. package/src/api/index.ts +25 -366
  71. package/src/api/page.ts +85 -0
  72. package/src/api/site.ts +51 -0
  73. package/src/api/system.ts +39 -0
  74. package/src/api/upload.ts +29 -0
  75. package/src/api/user.ts +75 -0
  76. package/src/artalk.ts +52 -46
  77. package/src/comment/actions.ts +3 -3
  78. package/src/comment/comment.ts +6 -9
  79. package/src/comment/render.ts +76 -40
  80. package/src/components/pagination.ts +0 -1
  81. package/src/context.ts +31 -31
  82. package/src/editor/editor.ts +2 -4
  83. package/src/editor/plugs/header-input-plug.ts +1 -1
  84. package/src/editor/plugs/upload-plug.ts +1 -1
  85. package/src/i18n/index.ts +117 -2
  86. package/src/layer/sidebar-layer.ts +1 -3
  87. package/src/lib/checker/admin-checker.ts +1 -1
  88. package/src/lib/checker/captcha-checker.ts +3 -3
  89. package/src/lib/stat.ts +2 -2
  90. package/src/lib/ui.ts +6 -0
  91. package/src/list/list-lite.ts +25 -25
  92. package/src/list/list.ts +3 -4
  93. package/src/style/main.less +6 -0
  94. package/types/context.d.ts +4 -1
  95. package/types/global.d.ts +0 -2
  96. package/vite-base.config.ts +9 -5
  97. package/vite.config.ts +1 -1
  98. package/types/index.d.ts +0 -3
@@ -0,0 +1,28 @@
1
+ import { CommentData } from './artalk-data'
2
+ import { LocalUser } from './artalk-config'
3
+
4
+ /** EventName to EventPayload Type */
5
+ export interface EventPayloadMap {
6
+ 'list-load': undefined // 评论加载时
7
+ 'list-loaded': undefined // 评论装载后
8
+ 'list-inserted': CommentData // 评论插入后
9
+ 'editor-submit': undefined // 编辑器提交时
10
+ 'editor-submitted': undefined // 编辑器提交后
11
+ 'user-changed': LocalUser // 本地用户数据变更时
12
+ 'conf-updated': undefined // Artalk 配置变更时
13
+ 'sidebar-show': undefined // 侧边栏显示
14
+ 'sidebar-hide': undefined // 侧边栏隐藏
15
+ }
16
+
17
+ // ============================================
18
+ export interface Handler<P> {
19
+ (payload: P): void
20
+ }
21
+
22
+ export type EventScopeType = 'internal'|'external'
23
+
24
+ export interface Event<K extends keyof EventPayloadMap = keyof EventPayloadMap> {
25
+ name: keyof EventPayloadMap
26
+ handler: Handler<EventPayloadMap[K]>
27
+ scope: EventScopeType
28
+ }
File without changes
@@ -0,0 +1,4 @@
1
+ import ContextApi from './context'
2
+
3
+ type ArtalkPlug = (ctx: ContextApi) => void
4
+ export default ArtalkPlug
package/index.html CHANGED
@@ -31,8 +31,8 @@
31
31
  .to-top { right: 25px; }
32
32
  </style>
33
33
  <!--<link rel="stylesheet"
34
- href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.1/styles/arta.min.css">
35
- <script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.1/highlight.min.js"></script>-->
34
+ href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/styles/arta.min.css">
35
+ <script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/highlight.min.js"></script>-->
36
36
 
37
37
  <!-- For mobile testing -->
38
38
  <script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script>
@@ -65,7 +65,7 @@
65
65
  import Artalk from './src/main'
66
66
  var artalk = new Artalk({
67
67
  el: '#comments',
68
- pageKey: 'https://artalk.js.org/',
68
+ pageKey: 'https://artalk.js.org/guide/intro.html',
69
69
  pageTitle: 'Artalk Home',
70
70
  server: (import.meta.env.DEV) ? 'http://localhost:23366' : 'https://artalk.qwqaq.com',
71
71
  site: 'ArtalkDocs',
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "artalk",
3
- "version": "2.3.4",
4
- "backendMinVersion": "2.1.10",
3
+ "version": "2.4.1",
4
+ "backendMinVersion": "2.2.0",
5
5
  "license": "LGPL-3.0",
6
6
  "description": "A Selfhosted Comment System",
7
7
  "keywords": [
@@ -22,14 +22,14 @@
22
22
  "unpkg": "./dist/Artalk.iife.js",
23
23
  "jsdelivr": "./dist/Artalk.iife.js",
24
24
  "module": "./dist/Artalk.es.js",
25
- "types": "./types/index.d.ts",
25
+ "types": "./dist/src/main.d.ts",
26
26
  "devDependencies": {
27
- "@types/marked": "4.0.3"
27
+ "@types/marked": "4.0.6"
28
28
  },
29
29
  "dependencies": {
30
30
  "hanabi": "^0.4.0",
31
31
  "insane": "^2.6.2",
32
- "marked": "^4.0.17",
32
+ "marked": "^4.0.19",
33
33
  "abortcontroller-polyfill": "^1.7.3"
34
34
  },
35
35
  "scripts": {
@@ -0,0 +1,18 @@
1
+ import ApiBase from './api-base'
2
+
3
+ /**
4
+ * 管理员 API
5
+ */
6
+ export default class AdminApi extends ApiBase {
7
+ /** 缓存清除 */
8
+ public cacheFlushAll() {
9
+ const params: any = { flush_all: true }
10
+ return this.POST('/admin/cache-flush', params)
11
+ }
12
+
13
+ /** 缓存预热 */
14
+ public cacheWarmUp() {
15
+ const params: any = {}
16
+ return this.POST('/admin/cache-warm', params)
17
+ }
18
+ }
@@ -0,0 +1,27 @@
1
+ import Context from '~/types/context'
2
+ import Api from '.'
3
+ import { POST, Fetch } from './request'
4
+
5
+ abstract class ApiBase {
6
+ protected api: Api
7
+ protected ctx: Context
8
+
9
+ constructor(api: Api, ctx: Context) {
10
+ this.api = api
11
+ this.ctx = ctx
12
+ }
13
+
14
+ protected async POST<T>(path: string, data?: {[key: string]: any}) {
15
+ return POST<T>(this.ctx, this.api.baseURL+path, data)
16
+ }
17
+
18
+ protected async Fetch(path: string, init: RequestInit, timeout?: number): Promise<any> {
19
+ return Fetch(this.ctx, this.api.baseURL+path, init, timeout)
20
+ }
21
+ }
22
+
23
+ interface ApiBase {
24
+
25
+ }
26
+
27
+ export default ApiBase
@@ -0,0 +1,24 @@
1
+ import ApiBase from './api-base'
2
+
3
+ /**
4
+ * 验证码 API
5
+ */
6
+ export default class CaptchaApi extends ApiBase {
7
+ /** 验证码 · 获取 */
8
+ public async captchaGet() {
9
+ const data = await this.POST<any>('/captcha/refresh')
10
+ return (data.img_data || '') as string
11
+ }
12
+
13
+ /** 验证码 · 检验 */
14
+ public async captchaCheck(value: string) {
15
+ const data = await this.POST<any>('/captcha/check', { value })
16
+ return (data.img_data || '') as string
17
+ }
18
+
19
+ /** 验证码 · 状态 */
20
+ public async captchaStatus() {
21
+ const data = await this.POST<any>('/captcha/status')
22
+ return (data || { is_pass: false }) as { is_pass: boolean }
23
+ }
24
+ }
@@ -0,0 +1,84 @@
1
+ import { CommentData, ListData } from '~/types/artalk-data'
2
+ import * as Utils from '../lib/utils'
3
+ import ApiBase from './api-base'
4
+
5
+ /**
6
+ * 评论 API
7
+ */
8
+ export default class CommentApi extends ApiBase {
9
+ /** 评论 · 获取 */
10
+ public get(offset: number, pageSize: number, flatMode?: boolean, paramsEditor?: (params: any) => void) {
11
+ const params: any = {
12
+ page_key: this.ctx.conf.pageKey,
13
+ site_name: this.ctx.conf.site || '',
14
+ limit: pageSize,
15
+ offset,
16
+ }
17
+
18
+ if (flatMode) params.flat_mode = flatMode // 平铺模式
19
+ if (this.ctx.user.checkHasBasicUserInfo()) {
20
+ params.name = this.ctx.user.data.nick
21
+ params.email = this.ctx.user.data.email
22
+ }
23
+
24
+ if (paramsEditor) paramsEditor(params)
25
+
26
+ return this.POST<ListData>('/get', params)
27
+ }
28
+
29
+ /** 评论 · 创建 */
30
+ public async add(comment: { nick: string, email: string, link: string, content: string, rid: number, page_key: string, page_title?: string, site_name?: string }) {
31
+ const params: any = {
32
+ name: comment.nick,
33
+ email: comment.email,
34
+ link: comment.link,
35
+ content: comment.content,
36
+ rid: comment.rid,
37
+ page_key: comment.page_key,
38
+ ua: await Utils.getCorrectUserAgent(), // 需要后端支持,获取修正后的 UA
39
+ }
40
+
41
+ if (comment.page_title) params.page_title = comment.page_title
42
+ if (comment.site_name) params.site_name = comment.site_name
43
+
44
+ const data = await this.POST<any>('/add', params)
45
+ return (data.comment as CommentData)
46
+ }
47
+
48
+ /** 评论 · 修改 */
49
+ public async commentEdit(data: Partial<CommentData>) {
50
+ const params: any = {
51
+ ...data,
52
+ }
53
+
54
+ const d = await this.POST<any>('/admin/comment-edit', params)
55
+ return (d.comment as CommentData)
56
+ }
57
+
58
+ /** 评论 · 删除 */
59
+ public commentDel(commentID: number, siteName?: string) {
60
+ const params: any = {
61
+ id: String(commentID),
62
+ site_name: siteName || '',
63
+ }
64
+
65
+ return this.POST('/admin/comment-del', params)
66
+ }
67
+
68
+ /** 投票 */
69
+ public async vote(targetID: number, type: string) {
70
+ const params: any = {
71
+ site_name: this.ctx.conf.site || '',
72
+ target_id: targetID,
73
+ type,
74
+ }
75
+
76
+ if (this.ctx.user.checkHasBasicUserInfo()) {
77
+ params.name = this.ctx.user.data.nick
78
+ params.email = this.ctx.user.data.email
79
+ }
80
+
81
+ const data = await this.POST<any>('/vote', params)
82
+ return (data as {up: number, down: number})
83
+ }
84
+ }
package/src/api/index.ts CHANGED
@@ -1,378 +1,37 @@
1
- import { CommentData, ListData, UserData, PageData, SiteData, NotifyData } from '~/types/artalk-data'
2
- import ArtalkConfig from '~/types/artalk-config'
3
1
  import Context from '~/types/context'
4
- import { Fetch, ToFormData, POST } from './request'
5
- import * as Utils from '../lib/utils'
6
2
  import 'abortcontroller-polyfill/dist/polyfill-patch-fetch'
7
3
 
8
- export default class Api {
9
- private ctx: Context
10
- private baseURL: string
4
+ import comment from './comment'
5
+ import page from './page'
6
+ import site from './site'
7
+ import user from './user'
8
+ import system from './system'
9
+ import captcha from './captcha'
10
+ import admin from './admin'
11
+ import upload from './upload'
12
+
13
+ const ApiComponents = {
14
+ comment, page, site,
15
+ user, system, captcha,
16
+ admin, upload
17
+ }
18
+
19
+ class Api {
20
+ protected ctx: Context
21
+ public baseURL: string
11
22
 
12
23
  constructor (ctx: Context) {
13
24
  this.ctx = ctx
14
25
  this.baseURL = `${ctx.conf.server}/api`
15
- }
16
-
17
- // ============================
18
- // 评论 Comment
19
- // ============================
20
-
21
- /** 评论 · 获取 */
22
- public get(offset: number, pageSize: number, flatMode?: boolean, paramsEditor?: (params: any) => void) {
23
- const params: any = {
24
- page_key: this.ctx.conf.pageKey,
25
- site_name: this.ctx.conf.site || '',
26
- limit: pageSize,
27
- offset,
28
- }
29
-
30
- if (flatMode) params.flat_mode = flatMode // 平铺模式
31
- if (this.ctx.user.checkHasBasicUserInfo()) {
32
- params.name = this.ctx.user.data.nick
33
- params.email = this.ctx.user.data.email
34
- }
35
-
36
- if (paramsEditor) paramsEditor(params)
37
-
38
- return POST<ListData>(this.ctx, `${this.baseURL}/get`, params)
39
- }
40
-
41
- /** 评论 · 创建 */
42
- public async add(comment: { nick: string, email: string, link: string, content: string, rid: number, page_key: string, page_title?: string, site_name?: string }) {
43
- const params: any = {
44
- name: comment.nick,
45
- email: comment.email,
46
- link: comment.link,
47
- content: comment.content,
48
- rid: comment.rid,
49
- page_key: comment.page_key,
50
- ua: await Utils.getCorrectUserAgent(), // 需要后端支持,获取修正后的 UA
51
- }
52
-
53
- if (comment.page_title) params.page_title = comment.page_title
54
- if (comment.site_name) params.site_name = comment.site_name
55
-
56
- const data = await POST<any>(this.ctx, `${this.baseURL}/add`, params)
57
- return (data.comment as CommentData)
58
- }
59
-
60
- /** 评论 · 修改 */
61
- public async commentEdit(data: Partial<CommentData>) {
62
- const params: any = {
63
- ...data,
64
- }
65
-
66
- const d = await POST<any>(this.ctx, `${this.baseURL}/admin/comment-edit`, params)
67
- return (d.comment as CommentData)
68
- }
69
-
70
- /** 评论 · 删除 */
71
- public commentDel(commentID: number, siteName?: string) {
72
- const params: any = {
73
- id: String(commentID),
74
- site_name: siteName || '',
75
- }
76
-
77
- return POST(this.ctx, `${this.baseURL}/admin/comment-del`, params)
78
- }
79
-
80
- // ============================
81
- // 用户 User
82
- // ============================
83
-
84
- /** 用户 · 登录 */
85
- public async login(name: string, email: string, password: string) {
86
- const params: any = {
87
- name, email, password
88
- }
89
-
90
- if (this.ctx.conf.site) params.site_name = this.ctx.conf.site
91
-
92
- const data = await POST<any>(this.ctx, `${this.baseURL}/login`, params)
93
- return (data.token as string)
94
- }
95
26
 
96
- /** 用户 · 获取 */
97
- public userGet(name: string, email: string) {
98
- const ctrl = new AbortController()
99
- const params: any = {
100
- name, email, site_name: (this.ctx.conf.site || '')
101
- }
102
-
103
- const req = Fetch(this.ctx, `${this.baseURL}/user-get`, {
104
- method: 'POST',
105
- body: ToFormData(params),
106
- signal: ctrl.signal,
107
- }).then((json) => ({
108
- user: json.data.user as UserData|null,
109
- is_login: json.data.is_login as boolean,
110
- unread: (json.data.unread || []) as NotifyData[],
111
- unread_count: json.data.unread_count || 0,
112
- }))
113
-
114
- return {
115
- req,
116
- abort: () => { ctrl.abort() },
117
- }
118
- }
119
-
120
- /** 用户 · 登录状态 */
121
- public async loginStatus() {
122
- const data = await POST<any>(this.ctx, `${this.baseURL}/login-status`, {
123
- name: this.ctx.user.data.nick,
124
- email: this.ctx.user.data.email
27
+ Object.entries(ApiComponents).forEach(([key, ApiComponent]) => {
28
+ this[key] = new ApiComponent(this, this.ctx)
125
29
  })
126
- return (data || { is_login: false, is_admin: false }) as { is_login: boolean, is_admin: boolean }
127
- }
128
-
129
- /** 用户 · 注销 */
130
- public async logout() {
131
- return POST(this.ctx, `${this.baseURL}/logout`)
132
- }
133
-
134
- // ============================
135
- // 页面 Page
136
- // ============================
137
-
138
- /** 页面 · 获取 */
139
- public async pageGet(siteName?: string, offset?: number, limit?: number) {
140
- const params: any = {
141
- site_name: siteName || '',
142
- offset: offset || 0,
143
- limit: limit || 15,
144
- }
145
-
146
- const d = await POST<any>(this.ctx, `${this.baseURL}/admin/page-get`, params)
147
- return (d as { pages: PageData[], total: number })
148
- }
149
-
150
- /** 页面 · 修改 */
151
- public async pageEdit(data: PageData) {
152
- const params: any = {
153
- id: data.id,
154
- key: data.key,
155
- title: data.title,
156
- admin_only: data.admin_only,
157
- site_name: data.site_name || this.ctx.conf.site,
158
- }
159
-
160
- const d = await POST<any>(this.ctx, `${this.baseURL}/admin/page-edit`, params)
161
- return (d.page as PageData)
162
- }
163
-
164
- /** 页面 · 删除 */
165
- public pageDel(pageKey: string, siteName?: string) {
166
- const params: any = {
167
- key: String(pageKey),
168
- site_name: siteName || '',
169
- }
170
-
171
- return POST(this.ctx, `${this.baseURL}/admin/page-del`, params)
172
- }
173
-
174
- /** 页面 · 数据更新 */
175
- public async pageFetch(id?: number, siteName?: string, getStatus?: boolean) {
176
- const params: any = {}
177
- if (id) params.id = id
178
- if (siteName) params.site_name = siteName
179
- if (getStatus) params.get_status = getStatus
180
-
181
- const d = await POST<any>(this.ctx, `${this.baseURL}/admin/page-fetch`, params)
182
- return (d as any)
183
- }
184
-
185
- // ============================
186
- // 站点 Site
187
- // ============================
188
-
189
- /** 站点 · 获取 */
190
- public async siteGet() {
191
- const params: any = {}
192
-
193
- const d = await POST<any>(this.ctx, `${this.baseURL}/admin/site-get`, params)
194
- return (d.sites as SiteData[])
195
- }
196
-
197
- /** 站点 · 创建 */
198
- public async siteAdd(name: string, urls: string) {
199
- const params: any = {
200
- name, urls,
201
- }
202
-
203
- const d = await POST<any>(this.ctx, `${this.baseURL}/admin/site-add`, params)
204
- return (d.site as SiteData)
205
- }
206
-
207
- /** 站点 · 修改 */
208
- public async siteEdit(data: SiteData) {
209
- const params: any = {
210
- id: data.id,
211
- name: data.name || '',
212
- urls: data.urls || '',
213
- }
214
-
215
- const d = await POST<any>(this.ctx, `${this.baseURL}/admin/site-edit`, params)
216
- return (d.site as SiteData)
217
- }
218
-
219
- /** 站点 · 删除 */
220
- public siteDel(id: number, delContent = false) {
221
- const params: any = { id, del_content: delContent }
222
-
223
- return POST(this.ctx, `${this.baseURL}/admin/site-del`, params)
224
- }
225
-
226
- /** 导出 */
227
- public async export() {
228
- const d = await Fetch(this.ctx, `${this.baseURL}/admin/export`, { method: 'POST' }, 0)
229
- return (d.data?.data || '' as string)
230
- }
231
-
232
- // ============================
233
- // 杂项
234
- // ============================
235
-
236
- /** 投票 */
237
- public async vote(targetID: number, type: string) {
238
- const params: any = {
239
- site_name: this.ctx.conf.site || '',
240
- target_id: targetID,
241
- type,
242
- }
243
-
244
- if (this.ctx.user.checkHasBasicUserInfo()) {
245
- params.name = this.ctx.user.data.nick
246
- params.email = this.ctx.user.data.email
247
- }
248
-
249
- const data = await POST<any>(this.ctx, `${this.baseURL}/vote`, params)
250
- return (data as {up: number, down: number})
251
- }
252
-
253
- /** 已读标记 */
254
- public markRead(notifyKey: string, readAll = false) {
255
- const params: any = {
256
- site_name: this.ctx.conf.site || '',
257
- notify_key: notifyKey,
258
- }
259
-
260
- if (readAll) {
261
- delete params.notify_key
262
- params.read_all = true
263
- params.name = this.ctx.user.data.nick
264
- params.email = this.ctx.user.data.email
265
- }
266
-
267
- return POST(this.ctx, `${this.baseURL}/mark-read`, params)
268
- }
269
-
270
- /** PV */
271
- public async pv() {
272
- const params: any = {
273
- site_name: this.ctx.conf.site || '',
274
- page_key: this.ctx.conf.pageKey || '',
275
- page_title: this.ctx.conf.pageTitle || ''
276
- }
277
-
278
- const p = await POST<any>(this.ctx, `${this.baseURL}/pv`, params)
279
- return p.pv as number
280
- }
281
-
282
- /** 统计 */
283
- public async stat(
284
- type: 'latest_comments'|'latest_pages'|'pv_most_pages'|'comment_most_pages'|
285
- 'page_pv'|'site_pv'|'page_comment'|'site_comment',
286
- pageKeys?: string|string[],
287
- limit?: number
288
- ) {
289
- const params: any = {
290
- type,
291
- site_name: this.ctx.conf.site || '',
292
- }
293
-
294
- if (pageKeys) params.page_keys = Array.isArray(pageKeys) ? pageKeys.join(',') : pageKeys
295
- if (limit) params.limit = limit
296
-
297
- const data = await POST<PageData[]|CommentData[]|object|number>(this.ctx, `${this.baseURL}/stat`, params)
298
- return data
299
- }
300
-
301
- /** 图片上传 */
302
- public async imgUpload(file: File) {
303
- const params: any = {
304
- name: this.ctx.user.data.nick,
305
- email: this.ctx.user.data.email,
306
- page_key: this.ctx.conf.pageKey,
307
- }
308
-
309
- if (this.ctx.conf.site) params.site_name = this.ctx.conf.site
310
-
311
- const form = ToFormData(params)
312
- form.set('file', file)
313
-
314
- const init: RequestInit = {
315
- method: 'POST',
316
- body: form
317
- }
318
-
319
- const json = await Fetch(this.ctx, `${this.baseURL}/img-upload`, init)
320
- return ((json.data || {}) as any) as { img_file: string, img_url: string }
321
- }
322
-
323
- /** 获取配置 */
324
- public async conf() {
325
- const data = await POST<any>(this.ctx, `${this.baseURL}/conf`)
326
- const conf = (data.frontend_conf || {}) as ArtalkConfig
327
-
328
- // Patch: `emoticons` config string to json
329
- if (conf.emoticons && typeof conf.emoticons === "string") {
330
- conf.emoticons = conf.emoticons.trim()
331
- if (conf.emoticons.startsWith("[") || conf.emoticons.startsWith("{")) {
332
- conf.emoticons = JSON.parse(conf.emoticons) // pase json
333
- } else if (conf.emoticons === "false") {
334
- conf.emoticons = false
335
- }
336
- }
337
-
338
- return conf
339
30
  }
31
+ }
340
32
 
341
- // ============================
342
- // 验证码
343
- // ============================
344
-
345
- /** 验证码 · 获取 */
346
- public async captchaGet() {
347
- const data = await POST<any>(this.ctx, `${this.baseURL}/captcha/refresh`)
348
- return (data.img_data || '') as string
349
- }
350
-
351
- /** 验证码 · 检验 */
352
- public async captchaCheck(value: string) {
353
- const data = await POST<any>(this.ctx, `${this.baseURL}/captcha/check`, { value })
354
- return (data.img_data || '') as string
355
- }
356
-
357
- /** 验证码 · 状态 */
358
- public async captchaStatus() {
359
- const data = await POST<any>(this.ctx, `${this.baseURL}/captcha/status`)
360
- return (data || { is_pass: false }) as { is_pass: boolean }
361
- }
362
-
363
- // ============================
364
- // 管理员缓存操作
365
- // ============================
366
-
367
- /** 缓存清除 */
368
- public cacheFlushAll() {
369
- const params: any = { flush_all: true }
370
- return POST(this.ctx, `${this.baseURL}/admin/cache-flush`, params)
371
- }
33
+ type TC = typeof ApiComponents
34
+ type AC = { [K in keyof TC]: InstanceType<TC[K]> }
35
+ interface Api extends AC {}
372
36
 
373
- /** 缓存预热 */
374
- public cacheWarmUp() {
375
- const params: any = {}
376
- return POST(this.ctx, `${this.baseURL}/admin/cache-warm`, params)
377
- }
378
- }
37
+ export default Api