diff --git a/resources/spa/CONTRIBUTING.md b/resources/spa/CONTRIBUTING.md index 5917ab05b..89df0471c 100644 --- a/resources/spa/CONTRIBUTING.md +++ b/resources/spa/CONTRIBUTING.md @@ -334,45 +334,6 @@ export default { 隐藏 dialog,缓慢下移淡出的动画 -### 图片上传组件 ImagePoster - -`@/components/ImagePoster.vue` - -用于各页面中图片上传相关内容,使用方法详见 `@/pages/profile/Certificate.vue` - -``` vue - - -``` - -#### `Slot` - -含有一个匿名 slot,支持任何 html 标签,显示在上传组件的 icon 下方 - -#### `Event` - -##### `uploaded` - -图片上传成功后的回调方法,接受一个参数,值为已上传的图片信息。 - -##### `error` - -图片上传失败的回调方法 - ### banner 轮播广告位 BannerAd `@/components/advertisement/BannerAd.vue` @@ -441,6 +402,38 @@ export default { 用于获取对应页面广告具体数据 + +### 文件上传 ImageUploader + +`@/components/common/ImageUploader.vue` + +用于新版本、老版本兼容的文件上传组件,参考话题封面上传 + +#### `Props` + +##### `type` {string} [id] + +- `id` +- `storage` +- `blob` +- `url` + +##### `value` {*} + +该属性的指取决于 `type` 的值 +- 为 `id` 时是老版本返回的文件 id +- 为 `storage` 时是新版本返回的 file node 节点 +- 为 `blob` 时是临时的blob对象 +- 为 `url` 时是临时的 url 地址 + +#### `Events` + +##### `@update:src` + +该属性返回的是一个图片临时地址,用于前端展示 + +`@update:src="src = $event"` + ## 表单组件 FormItem 表单组件用于快速构建样式和交互方式统一的表单项 diff --git a/resources/spa/package.json b/resources/spa/package.json index 53c5dd4e5..8227e78e2 100644 --- a/resources/spa/package.json +++ b/resources/spa/package.json @@ -1,7 +1,7 @@ { "name": "@slimkit/plus-small-screen-client", "private": true, - "version": "4.2.3", + "version": "4.3.0", "scripts": { "serve": "vue-cli-service serve", "build": "vue-cli-service build", diff --git a/resources/spa/src/api/topic.js b/resources/spa/src/api/topic.js new file mode 100644 index 000000000..aa903db8b --- /dev/null +++ b/resources/spa/src/api/topic.js @@ -0,0 +1,36 @@ +import api from './api' + +/** + * 获取话题列表 + * + * @author mutoe + * @export + * @param {Object} params + * @param {string} [params.q] 搜索关键字 + * @param {number} [params.limit=15] + * @param {string} [params.direction=desc] + * @param {number} [params.index=0] + * @param {string} [params.only] 是否热门 'hot' + * @returns + */ +export function getTopicList (params) { + if (params.q === '') return Promise.resolve({ data: [] }) + const url = '/feed/topics' + return api.get(url, { params, validateStatus: s => s === 200 }) +} + +/** + * 创建话题 + * + * @author mutoe + * @export + * @param {Object} data + * @param {string} data.name 话题名称 + * @param {string} [data.desc] 描述 + * @param {string} [data.logo] file node 节点 + * @returns + */ +export function createTopic (data) { + const url = '/feed/topics' + return api.post(url, data, { validateStatus: s => s === 201 }) +} diff --git a/resources/spa/src/components/common/ImageUploader.vue b/resources/spa/src/components/common/ImageUploader.vue new file mode 100644 index 000000000..751c47f2e --- /dev/null +++ b/resources/spa/src/components/common/ImageUploader.vue @@ -0,0 +1,166 @@ + + + + + diff --git a/resources/spa/src/components/common/SearchBar.vue b/resources/spa/src/components/common/SearchBar.vue index 492f989d8..3a1870cba 100644 --- a/resources/spa/src/components/common/SearchBar.vue +++ b/resources/spa/src/components/common/SearchBar.vue @@ -1,9 +1,6 @@ diff --git a/resources/spa/src/page/topic/TopicCreate.vue b/resources/spa/src/page/topic/TopicCreate.vue new file mode 100644 index 000000000..ebc146fdd --- /dev/null +++ b/resources/spa/src/page/topic/TopicCreate.vue @@ -0,0 +1,277 @@ + + + + + + + diff --git a/resources/spa/src/page/topic/TopicDetail.vue b/resources/spa/src/page/topic/TopicDetail.vue new file mode 100644 index 000000000..ed34663c1 --- /dev/null +++ b/resources/spa/src/page/topic/TopicDetail.vue @@ -0,0 +1,343 @@ + + + + + diff --git a/resources/spa/src/page/topic/TopicHome.vue b/resources/spa/src/page/topic/TopicHome.vue new file mode 100644 index 000000000..3933cd624 --- /dev/null +++ b/resources/spa/src/page/topic/TopicHome.vue @@ -0,0 +1,124 @@ + + + + + diff --git a/resources/spa/src/page/topic/TopicSearch.vue b/resources/spa/src/page/topic/TopicSearch.vue new file mode 100644 index 000000000..195744de6 --- /dev/null +++ b/resources/spa/src/page/topic/TopicSearch.vue @@ -0,0 +1,38 @@ + + + + + diff --git a/resources/spa/src/page/topic/components/TopicCard.vue b/resources/spa/src/page/topic/components/TopicCard.vue new file mode 100644 index 000000000..d3cfce9ef --- /dev/null +++ b/resources/spa/src/page/topic/components/TopicCard.vue @@ -0,0 +1,53 @@ + + + + + diff --git a/resources/spa/src/page/topic/components/TopicList.vue b/resources/spa/src/page/topic/components/TopicList.vue new file mode 100644 index 000000000..80ef69d3f --- /dev/null +++ b/resources/spa/src/page/topic/components/TopicList.vue @@ -0,0 +1,36 @@ + + + + + diff --git a/resources/spa/src/page/topic/components/TopicSearchPanel.vue b/resources/spa/src/page/topic/components/TopicSearchPanel.vue new file mode 100644 index 000000000..5e6204ff0 --- /dev/null +++ b/resources/spa/src/page/topic/components/TopicSearchPanel.vue @@ -0,0 +1,154 @@ + + + + + + + diff --git a/resources/spa/src/routers/routes.js b/resources/spa/src/routers/routes.js index 243e106c7..f7a1495fc 100755 --- a/resources/spa/src/routers/routes.js +++ b/resources/spa/src/routers/routes.js @@ -9,6 +9,7 @@ import groupRoutes from './group.js' import messageRoutes from './message.js' import questionRoutes from './question.js' import profileRoutes from './profile.js' +import topicRoutes from './topic.js' const router = [ /* 入口重定向 */ @@ -24,6 +25,7 @@ const router = [ ...messageRoutes, ...questionRoutes, ...profileRoutes, + ...topicRoutes, { path: '*', component: NotFound }, /* 404 页面 */ ] diff --git a/resources/spa/src/routers/topic.js b/resources/spa/src/routers/topic.js new file mode 100644 index 000000000..a5aea3264 --- /dev/null +++ b/resources/spa/src/routers/topic.js @@ -0,0 +1,33 @@ +import TopicHome from '@/page/topic/TopicHome.vue' +import TopicCreate from '@/page/topic/TopicCreate.vue' +import TopicSearch from '@/page/topic/TopicSearch.vue' + +export default [ + { + path: '/topic', + name: 'TopicHome', + component: TopicHome, + meta: { + title: '话题', + }, + }, + { + path: '/topic/create', + name: 'TopicCreate', + component: TopicCreate, + meta: { + title: '创建话题', + requiresAuth: true, + }, + }, + { + path: '/topic/search', + name: 'TopicSearch', + component: TopicSearch, + meta: { + title: '搜索话题', + keepAlive: true, + requiresAuth: true, + }, + }, +] diff --git a/resources/spa/src/stores/module/index.js b/resources/spa/src/stores/module/index.js index d5a6e7c6f..3eb50e9c0 100644 --- a/resources/spa/src/stores/module/index.js +++ b/resources/spa/src/stores/module/index.js @@ -8,6 +8,7 @@ import news from './news' import group from './group' import feed from './feed' import user from './user' +import topic from './topic' export default { rank, @@ -20,4 +21,5 @@ export default { group, feed, user, + topic, } diff --git a/resources/spa/src/stores/module/topic.js b/resources/spa/src/stores/module/topic.js new file mode 100644 index 000000000..ebaad7942 --- /dev/null +++ b/resources/spa/src/stores/module/topic.js @@ -0,0 +1,49 @@ +import * as api from '@/api/topic' +import { limit } from '@/api' + +export const TYPES = { + SAVE_TOPIC_LIST: 'SAVE_TOPIC_LIST', +} + +const state = { + hotList: [], + newList: [], +} + +const getters = {} + +const mutations = { + [TYPES.SAVE_TOPIC_LIST] (state, payload) { + let { list, type, reset = false } = payload + type = type === 'hot' ? 'hotList' : 'newList' + if (reset) { + state[type] = list + } else { + state[type].push(...list) + } + }, +} + +const actions = { + /** + * 获取动态列表 + * + * @author mutoe + * @returns {boolean} noMore? + */ + async fetchTopicList ({ commit }, payload) { + const { params = {}, reset, type } = payload + if (type === 'hot') params.only = 'hot' + const { data: list = [] } = await api.getTopicList(params) + commit(TYPES.SAVE_TOPIC_LIST, { list, type, reset }) + return list.length < limit + }, +} + +export default { + namespaced: true, + state, + getters, + mutations, + actions, +}