Compare commits
4 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
3a86eb8fa2 | |
|
|
b89010ed51 | |
|
|
53edab4f35 | |
|
|
646953d544 |
|
|
@ -1,2 +1,3 @@
|
||||||
{
|
{
|
||||||
|
"typescript.tsdk": "node_modules\\typescript\\lib"
|
||||||
}
|
}
|
||||||
|
|
@ -62,7 +62,6 @@
|
||||||
"antd-mobile-icons": "^0.3.0",
|
"antd-mobile-icons": "^0.3.0",
|
||||||
"classnames": "^2.3.1",
|
"classnames": "^2.3.1",
|
||||||
"crypto-browserify": "3.12.0",
|
"crypto-browserify": "3.12.0",
|
||||||
"readable-stream": "3.6.2",
|
|
||||||
"crypto-js": "^4.1.1",
|
"crypto-js": "^4.1.1",
|
||||||
"dayjs": "^1.11.5",
|
"dayjs": "^1.11.5",
|
||||||
"echarts": "^5.3.0",
|
"echarts": "^5.3.0",
|
||||||
|
|
@ -95,6 +94,7 @@
|
||||||
"react-responsive": "^9.0.0-beta.10",
|
"react-responsive": "^9.0.0-beta.10",
|
||||||
"react-router-dom": "^6.4.0",
|
"react-router-dom": "^6.4.0",
|
||||||
"react-slick": "^0.29.0",
|
"react-slick": "^0.29.0",
|
||||||
|
"readable-stream": "3.6.2",
|
||||||
"rmc-pull-to-refresh": "^1.0.13",
|
"rmc-pull-to-refresh": "^1.0.13",
|
||||||
"uuid": "^8.3.2"
|
"uuid": "^8.3.2"
|
||||||
},
|
},
|
||||||
|
|
@ -205,7 +205,8 @@
|
||||||
"webpack": "^5.86.0",
|
"webpack": "^5.86.0",
|
||||||
"webpack-dev-server": "^4.15.1",
|
"webpack-dev-server": "^4.15.1",
|
||||||
"webpack-manifest-plugin": "^4.0.2",
|
"webpack-manifest-plugin": "^4.0.2",
|
||||||
"workbox-webpack-plugin": "^6.4.1"
|
"workbox-webpack-plugin": "^6.4.1",
|
||||||
|
"typescript-plugin-css-modules": "^5.1.0"
|
||||||
},
|
},
|
||||||
"browserslist": {
|
"browserslist": {
|
||||||
"production": [
|
"production": [
|
||||||
|
|
@ -230,4 +231,4 @@
|
||||||
"readable-stream": "3.6.2"
|
"readable-stream": "3.6.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,24 +14,6 @@ const checkers: Checker<EntityDict, 'essay', RuntimeCxt>[] = [
|
||||||
$or: [{ iState: 'unpublished' }, { iState: 'withdrawn' }],
|
$or: [{ iState: 'unpublished' }, { iState: 'withdrawn' }],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// settop的时候只能是isTop为false的
|
|
||||||
{
|
|
||||||
entity: 'essay',
|
|
||||||
action: 'setTop',
|
|
||||||
type: 'row',
|
|
||||||
filter: {
|
|
||||||
isTop: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// cancelTop的时候只能是isTop为true的
|
|
||||||
{
|
|
||||||
entity: 'essay',
|
|
||||||
action: 'cancelTop',
|
|
||||||
type: 'row',
|
|
||||||
filter: {
|
|
||||||
isTop: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// 在删除essay的时候,同步删除extraFile和essayLabels还有log
|
// 在删除essay的时候,同步删除extraFile和essayLabels还有log
|
||||||
// 注意,在checker中为非异步环境,这点与trigger不同
|
// 注意,在checker中为非异步环境,这点与trigger不同
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Styles from './styles.module.less';
|
import Styles from './styles.module.less';
|
||||||
import CategoryList from './categories';
|
import CategoryList from './categories';
|
||||||
import { useHomeContext } from './context/homeContext';
|
|
||||||
|
|
||||||
const FrontendHeader = () => {
|
const FrontendHeader = () => {
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,28 @@
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
height: 40px;
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
|
// 内部文字居中
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 10px;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: #1890ff;
|
color: #1890ff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.noCategory {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 40px;
|
||||||
|
color: #666;
|
||||||
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
@ -49,7 +49,7 @@ const CategoryList = (
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div>{t('noCategaries')}</div>
|
<div className={Styles.noCategory}>{t('noCategaries')}</div>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,9 @@ export default OakComponent({
|
||||||
// 先按置顶排序
|
// 先按置顶排序
|
||||||
sorter: {
|
sorter: {
|
||||||
$attr: {
|
$attr: {
|
||||||
isTop: 1,
|
topState: 1,
|
||||||
},
|
},
|
||||||
$direction: 'desc',
|
$direction: 'asc',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -98,6 +98,7 @@ export default OakComponent({
|
||||||
cover: '',
|
cover: '',
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
|
searchParam: this.props.searchParam
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { EntityDict } from '@project/oak-app-domain';
|
import { EntityDict } from '@project/oak-app-domain';
|
||||||
import { RowWithActions, WebComponentProps } from 'oak-frontend-base';
|
import { RowWithActions } from 'oak-frontend-base';
|
||||||
import Styles from './styles.module.less';
|
import Styles from './styles.module.less';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import useFeatures from '@project/hooks/useFeatures';
|
import useFeatures from '@project/hooks/useFeatures';
|
||||||
|
|
@ -19,8 +19,6 @@ const EssayItem = (props: {
|
||||||
};
|
};
|
||||||
}) => {
|
}) => {
|
||||||
const { item, navigateTo, t, searchParam } = props;
|
const { item, navigateTo, t, searchParam } = props;
|
||||||
const features = useFeatures();
|
|
||||||
// features.extraFile.
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
@ -46,7 +44,7 @@ const EssayItem = (props: {
|
||||||
</div>
|
</div>
|
||||||
<div className={Styles.body}>
|
<div className={Styles.body}>
|
||||||
<div className={Styles.title}>
|
<div className={Styles.title}>
|
||||||
{item.isTop && (
|
{item.topState === 'top' && (
|
||||||
<div className={Styles.top}>
|
<div className={Styles.top}>
|
||||||
{t('common::top')}
|
{t('common::top')}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,19 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.noCover {
|
||||||
|
width: 200px;
|
||||||
|
height: 120px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
background: #f0f0f0;
|
||||||
|
color: #666;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
.body {
|
.body {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
|
||||||
|
|
@ -97,5 +110,10 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.creator {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -83,4 +83,9 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.categories {
|
||||||
|
// 放一个属性但是不影响任何东西
|
||||||
|
display: inherit;
|
||||||
}
|
}
|
||||||
|
|
@ -116,6 +116,18 @@ const i18ns: I18n[] = [
|
||||||
"tips": "请选择模式"
|
"tips": "请选择模式"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: "b4b7c9f5d8cc5466e9424d7538ff0176",
|
||||||
|
namespace: "new-demo-p-frontend-essay-details",
|
||||||
|
language: "zh-CN",
|
||||||
|
module: "new-demo",
|
||||||
|
position: "src/pages/frontend/essay/details",
|
||||||
|
data: {
|
||||||
|
"like": "点赞",
|
||||||
|
"liked": "已点赞",
|
||||||
|
"unlike": "取消点赞"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: "aa6631e469935d0fb5c556e96dcc4379",
|
id: "aa6631e469935d0fb5c556e96dcc4379",
|
||||||
namespace: "new-demo-p-frontend-home",
|
namespace: "new-demo-p-frontend-home",
|
||||||
|
|
@ -616,19 +628,25 @@ const i18ns: I18n[] = [
|
||||||
"logs": "修改记录",
|
"logs": "修改记录",
|
||||||
"category": "分类",
|
"category": "分类",
|
||||||
"iState": "状态",
|
"iState": "状态",
|
||||||
"isTop": "是否置顶"
|
"topState": "置顶状态"
|
||||||
},
|
},
|
||||||
"action": {
|
"action": {
|
||||||
"publish": "发布",
|
"publish": "发布",
|
||||||
"withdraw": "撤回",
|
"withdraw": "撤回",
|
||||||
"setTop": "置顶",
|
"setTop": "置顶",
|
||||||
"cancelTop": "取消置顶"
|
"cancelTop": "取消置顶",
|
||||||
|
"like": "点赞",
|
||||||
|
"unlike": "取消点赞"
|
||||||
},
|
},
|
||||||
"v": {
|
"v": {
|
||||||
"iState": {
|
"iState": {
|
||||||
"unpublished": "未发布",
|
"unpublished": "未发布",
|
||||||
"published": "已发布",
|
"published": "已发布",
|
||||||
"withdrawn": "已撤回"
|
"withdrawn": "已撤回"
|
||||||
|
},
|
||||||
|
"topState": {
|
||||||
|
"top": "置顶",
|
||||||
|
"normal": "普通"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -747,6 +765,20 @@ const i18ns: I18n[] = [
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: "b9691c35f8511fb42aa59cbcc8645610",
|
||||||
|
namespace: "like",
|
||||||
|
language: "zh-CN",
|
||||||
|
module: "",
|
||||||
|
position: "oak-app-domain/Like",
|
||||||
|
data: {
|
||||||
|
"name": "点赞记录",
|
||||||
|
"attr": {
|
||||||
|
"essay": "文章",
|
||||||
|
"user": "用户"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: "f3c966c0e1deb4ca4c10e10117143849",
|
id: "f3c966c0e1deb4ca4c10e10117143849",
|
||||||
namespace: "livestream",
|
namespace: "livestream",
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ export interface Schema extends EntityShape {
|
||||||
images: ExtraFile[];
|
images: ExtraFile[];
|
||||||
logs: Log[];
|
logs: Log[];
|
||||||
category?: Category;
|
category?: Category;
|
||||||
isTop: Boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type IState = 'unpublished' | 'published' | 'withdrawn';
|
export type IState = 'unpublished' | 'published' | 'withdrawn';
|
||||||
|
|
@ -33,9 +32,22 @@ export const IActionDef: ActionDef<IAction, IState> = {
|
||||||
};
|
};
|
||||||
|
|
||||||
// 用户行为操作
|
// 用户行为操作
|
||||||
export type CommonAction = 'setTop' | 'cancelTop';
|
export type TopAction = 'setTop' | 'cancelTop';
|
||||||
|
|
||||||
type Action = IAction | CommonAction;
|
export type TopState = 'top' | 'normal';
|
||||||
|
|
||||||
|
export const TopActionDef: ActionDef<TopAction, TopState> = {
|
||||||
|
stm: {
|
||||||
|
setTop: ['normal', 'top'],
|
||||||
|
cancelTop: ['top', 'normal'],
|
||||||
|
},
|
||||||
|
is: 'normal',
|
||||||
|
};
|
||||||
|
|
||||||
|
// 点赞操作
|
||||||
|
export type LikeAction = 'like' | 'unlike';
|
||||||
|
|
||||||
|
type Action = IAction | TopAction | LikeAction;
|
||||||
|
|
||||||
export const entityDesc: EntityDesc<
|
export const entityDesc: EntityDesc<
|
||||||
Schema,
|
Schema,
|
||||||
|
|
@ -43,6 +55,7 @@ export const entityDesc: EntityDesc<
|
||||||
'',
|
'',
|
||||||
{
|
{
|
||||||
iState: IState;
|
iState: IState;
|
||||||
|
topState: TopState;
|
||||||
}
|
}
|
||||||
> = {
|
> = {
|
||||||
locales: {
|
locales: {
|
||||||
|
|
@ -58,13 +71,15 @@ export const entityDesc: EntityDesc<
|
||||||
logs: '修改记录',
|
logs: '修改记录',
|
||||||
category: '分类',
|
category: '分类',
|
||||||
iState: '状态',
|
iState: '状态',
|
||||||
isTop: '是否置顶',
|
topState: '置顶状态',
|
||||||
},
|
},
|
||||||
action: {
|
action: {
|
||||||
publish: '发布',
|
publish: '发布',
|
||||||
withdraw: '撤回',
|
withdraw: '撤回',
|
||||||
setTop: '置顶',
|
setTop: '置顶',
|
||||||
cancelTop: '取消置顶',
|
cancelTop: '取消置顶',
|
||||||
|
like: '点赞',
|
||||||
|
unlike: '取消点赞',
|
||||||
},
|
},
|
||||||
v: {
|
v: {
|
||||||
iState: {
|
iState: {
|
||||||
|
|
@ -72,6 +87,10 @@ export const entityDesc: EntityDesc<
|
||||||
published: '已发布',
|
published: '已发布',
|
||||||
withdrawn: '已撤回',
|
withdrawn: '已撤回',
|
||||||
},
|
},
|
||||||
|
topState: {
|
||||||
|
top: '置顶',
|
||||||
|
normal: '普通',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -83,6 +102,10 @@ export const entityDesc: EntityDesc<
|
||||||
published: '#87d068',
|
published: '#87d068',
|
||||||
withdrawn: '#2db7f5',
|
withdrawn: '#2db7f5',
|
||||||
},
|
},
|
||||||
|
topState: {
|
||||||
|
top: '#f50',
|
||||||
|
normal: '#87d068',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
indexes: [
|
indexes: [
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { EntityDesc, EntityShape } from 'oak-domain/lib/types';
|
||||||
|
import { Schema as Essay } from './Essay';
|
||||||
|
import { Schema as User } from 'oak-general-business/lib/entities/User';
|
||||||
|
|
||||||
|
// Like.ts
|
||||||
|
// 关联文章和用户,表示点赞记录
|
||||||
|
export interface Schema extends EntityShape {
|
||||||
|
essay: Essay;
|
||||||
|
user: User;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const entityDesc: EntityDesc<Schema> = {
|
||||||
|
locales: {
|
||||||
|
zh_CN: {
|
||||||
|
name: '点赞记录',
|
||||||
|
attr: {
|
||||||
|
essay: '文章',
|
||||||
|
user: '用户',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
@ -9,9 +9,9 @@ export default OakComponent({
|
||||||
// 先按置顶排序
|
// 先按置顶排序
|
||||||
sorter: {
|
sorter: {
|
||||||
$attr: {
|
$attr: {
|
||||||
isTop: 1,
|
topState: 1,
|
||||||
},
|
},
|
||||||
$direction: 'desc',
|
$direction: 'asc',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -52,5 +52,5 @@ export default OakComponent({
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
actions: ['update', 'withdraw', 'publish', 'setTop', 'cancelTop', 'remove'],
|
actions: ['update', 'withdraw', 'publish', 'remove', 'setTop', 'cancelTop'],
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -28,4 +28,17 @@
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.noCover {
|
||||||
|
width: 100px;
|
||||||
|
height: 50px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
background: #f0f0f0;
|
||||||
|
color: #666;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
|
|
@ -11,6 +11,7 @@ import Styles from './web.pc.module.less';
|
||||||
import { Button, Image, Tag } from 'antd';
|
import { Button, Image, Tag } from 'antd';
|
||||||
import Modal from 'antd/es/modal/Modal';
|
import Modal from 'antd/es/modal/Modal';
|
||||||
import EssayUpsert from '@project/components/console/essay/upsert';
|
import EssayUpsert from '@project/components/console/essay/upsert';
|
||||||
|
import { Action } from '@project/oak-app-domain/Essay/Action';
|
||||||
|
|
||||||
const EssayList = (
|
const EssayList = (
|
||||||
props: WebComponentProps<
|
props: WebComponentProps<
|
||||||
|
|
@ -67,7 +68,7 @@ const EssayList = (
|
||||||
render: (row) => {
|
render: (row) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{row.isTop ? (
|
{row.topState === "top" ? (
|
||||||
<Tag color='#f50'>{t('essay.isTop')}</Tag>
|
<Tag color='#f50'>{t('essay.isTop')}</Tag>
|
||||||
) : (
|
) : (
|
||||||
<Tag color='#108ee9'>{t('essay.notTop')}</Tag>
|
<Tag color='#108ee9'>{t('essay.notTop')}</Tag>
|
||||||
|
|
@ -208,20 +209,16 @@ const EssayList = (
|
||||||
updateItem({}, row.id, 'remove');
|
updateItem({}, row.id, 'remove');
|
||||||
execute();
|
execute();
|
||||||
break;
|
break;
|
||||||
// 置顶和取消置顶
|
|
||||||
case 'setTop':
|
|
||||||
case 'cancelTop':
|
|
||||||
updateItem({}, row.id, action);
|
|
||||||
execute();
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
|
updateItem({}, row.id, action as Action);
|
||||||
|
execute();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PageHeader
|
<PageHeader
|
||||||
title={<div className={Styles.left}>{t('essayList')}</div>}
|
title={t('essayList')}
|
||||||
extra={
|
extra={
|
||||||
<Button
|
<Button
|
||||||
type='primary'
|
type='primary'
|
||||||
|
|
@ -245,7 +242,7 @@ const EssayList = (
|
||||||
/>
|
/>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
<Modal
|
<Modal
|
||||||
title={t('label:selectLabels')}
|
title={t('label.selectLabels')}
|
||||||
open={showSelectLabels}
|
open={showSelectLabels}
|
||||||
onCancel={() => setShowSelectLabels(false)}
|
onCancel={() => setShowSelectLabels(false)}
|
||||||
onOk={() => {
|
onOk={() => {
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,10 @@ export default OakComponent({
|
||||||
isList: false,
|
isList: false,
|
||||||
projection: essayProjection,
|
projection: essayProjection,
|
||||||
formData({ data }) {
|
formData({ data }) {
|
||||||
|
const isLiked = data?.like$essay?.some(item => {
|
||||||
|
return item.user.id === this.features.token.getUserId();
|
||||||
|
})
|
||||||
|
const likeNums = data?.like$essay?.length || 0;
|
||||||
const fileIndex = data?.extraFile$entity?.findIndex(
|
const fileIndex = data?.extraFile$entity?.findIndex(
|
||||||
(item) => item.tag1 === 'cover'
|
(item) => item.tag1 === 'cover'
|
||||||
);
|
);
|
||||||
|
|
@ -16,11 +20,15 @@ export default OakComponent({
|
||||||
item: data,
|
item: data,
|
||||||
// 获取封面的url地址
|
// 获取封面的url地址
|
||||||
cover: url,
|
cover: url,
|
||||||
|
isLiked,
|
||||||
|
likeNums
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
item: data,
|
item: data,
|
||||||
cover: '',
|
cover: '',
|
||||||
|
isLiked,
|
||||||
|
likeNums
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"like": "点赞",
|
||||||
|
"liked": "已点赞",
|
||||||
|
"unlike": "取消点赞"
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,22 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
|
.back {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nums {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.likes {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.top {
|
.top {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import MdViewer from '@project/components/common/byteMD/MdViewer';
|
||||||
import FrontendFooter from '@project/components/frontend/home/FrontendFooter';
|
import FrontendFooter from '@project/components/frontend/home/FrontendFooter';
|
||||||
import { Button } from 'antd';
|
import { Button } from 'antd';
|
||||||
import { VerticalAlignTopOutlined } from '@ant-design/icons';
|
import { VerticalAlignTopOutlined } from '@ant-design/icons';
|
||||||
|
import OakIcon from 'oak-frontend-base/es/components/icon';
|
||||||
|
|
||||||
const EssayDetails = (
|
const EssayDetails = (
|
||||||
props: WebComponentProps<
|
props: WebComponentProps<
|
||||||
|
|
@ -15,11 +16,14 @@ const EssayDetails = (
|
||||||
{
|
{
|
||||||
item: RowWithActions<EntityDict, 'essay'>;
|
item: RowWithActions<EntityDict, 'essay'>;
|
||||||
cover: string;
|
cover: string;
|
||||||
|
isLiked: boolean;
|
||||||
|
likeNums: number;
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
) => {
|
) => {
|
||||||
const { item, cover } = props.data;
|
const { item, cover, isLiked, likeNums } = props.data;
|
||||||
const [showScrollTop, setShowScrollTop] = useState(false);
|
const [showScrollTop, setShowScrollTop] = useState(false);
|
||||||
|
const { t, update, execute } = props.methods;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleScroll = () => {
|
const handleScroll = () => {
|
||||||
|
|
@ -74,6 +78,32 @@ const EssayDetails = (
|
||||||
>
|
>
|
||||||
返回
|
返回
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
<div className={Styles.likes}>
|
||||||
|
{isLiked ? (
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
update({
|
||||||
|
}, 'unlike');
|
||||||
|
execute();
|
||||||
|
}}
|
||||||
|
shape='circle'
|
||||||
|
>
|
||||||
|
<OakIcon name='praise_fill' size={24} />
|
||||||
|
</Button>
|
||||||
|
) : (
|
||||||
|
<Button
|
||||||
|
shape='circle'
|
||||||
|
onClick={() => {
|
||||||
|
update({}, 'like');
|
||||||
|
execute();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<OakIcon name='praise' size={24} />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
<div className={Styles.nums}>{likeNums}</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<MdViewer md={item.content!} />
|
<MdViewer md={item.content!} />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import { EntityDict } from '@oak-app-domain';
|
||||||
import { Trigger } from 'oak-domain/lib/types';
|
import { Trigger } from 'oak-domain/lib/types';
|
||||||
import { BackendRuntimeContext } from '../context/BackendRuntimeContext';
|
import { BackendRuntimeContext } from '../context/BackendRuntimeContext';
|
||||||
import assert from 'assert';
|
import assert from 'assert';
|
||||||
|
import { generateNewIdAsync } from 'oak-domain/lib/utils/uuid';
|
||||||
|
|
||||||
const triggers: Trigger<EntityDict, 'essay', BackendRuntimeContext>[] = [
|
const triggers: Trigger<EntityDict, 'essay', BackendRuntimeContext>[] = [
|
||||||
{
|
{
|
||||||
|
|
@ -14,7 +15,6 @@ const triggers: Trigger<EntityDict, 'essay', BackendRuntimeContext>[] = [
|
||||||
assert(data && !(data instanceof Array));
|
assert(data && !(data instanceof Array));
|
||||||
// 若不存在meta,则初始化一个空对象
|
// 若不存在meta,则初始化一个空对象
|
||||||
data.meta = data.meta || {};
|
data.meta = data.meta || {};
|
||||||
data.isTop = data.isTop || false;
|
|
||||||
assert(data.content, 'content is required');
|
assert(data.content, 'content is required');
|
||||||
if (!data.summary) {
|
if (!data.summary) {
|
||||||
// 自动截取前面100个字符,加上省略号
|
// 自动截取前面100个字符,加上省略号
|
||||||
|
|
@ -23,35 +23,60 @@ const triggers: Trigger<EntityDict, 'essay', BackendRuntimeContext>[] = [
|
||||||
? data.content.slice(0, 100) + '...'
|
? data.content.slice(0, 100) + '...'
|
||||||
: data.content;
|
: data.content;
|
||||||
}
|
}
|
||||||
return 1;
|
return 0;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// action: setTop的时候设置isTop为true
|
// 调用like的action的时候,创建点赞的记录
|
||||||
{
|
{
|
||||||
name: '置顶时设置isTop为true',
|
name: "调用like的action的时候,创建点赞的记录",
|
||||||
entity: 'essay',
|
entity: "essay",
|
||||||
action: 'setTop',
|
action: "like",
|
||||||
when: 'before',
|
when: "before",
|
||||||
fn: async ({ operation }, context, option) => {
|
fn: async ({ operation }, context, option) => {
|
||||||
const { id, data } = operation;
|
const { filter } = operation;
|
||||||
assert(data && !(data instanceof Array));
|
assert(filter && filter.id, "filter is required");
|
||||||
data.isTop = true;
|
const eId = filter.id;
|
||||||
return 1;
|
const userId = context.getCurrentUserId();
|
||||||
},
|
// 创建点赞记录
|
||||||
|
const opres = await context.operate("like", {
|
||||||
|
id: await generateNewIdAsync(),
|
||||||
|
action: "create",
|
||||||
|
data: {
|
||||||
|
id: await generateNewIdAsync(),
|
||||||
|
essayId: eId as string,
|
||||||
|
userId,
|
||||||
|
}
|
||||||
|
}, option)
|
||||||
|
|
||||||
|
return opres.like?.create || 0;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
// action: cancelTop的时候设置isTop为false
|
// 调用unlike的action的时候,移除点赞的记录
|
||||||
{
|
{
|
||||||
name: '取消置顶时设置isTop为false',
|
name: "调用unlike的action的时候,移除点赞的记录",
|
||||||
entity: 'essay',
|
entity: "essay",
|
||||||
action: 'cancelTop',
|
action: "unlike",
|
||||||
when: 'before',
|
when: "before",
|
||||||
fn: async ({ operation }, context, option) => {
|
fn: async ({ operation }, context, option) => {
|
||||||
const { id, data } = operation;
|
const { filter, data } = operation;
|
||||||
assert(data && !(data instanceof Array));
|
assert(filter && filter.id, "filter is required");
|
||||||
data.isTop = false;
|
const eId = filter.id;
|
||||||
return 1;
|
const userId = context.getCurrentUserId();
|
||||||
},
|
// 创建点赞记录
|
||||||
},
|
const opres = await context.operate("like", {
|
||||||
|
id: await generateNewIdAsync(),
|
||||||
|
action: "remove",
|
||||||
|
data: {
|
||||||
|
},
|
||||||
|
filter: {
|
||||||
|
essayId: eId as string,
|
||||||
|
userId,
|
||||||
|
}
|
||||||
|
}, option)
|
||||||
|
|
||||||
|
return opres.like?.remove || 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
export default triggers;
|
export default triggers;
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ const triggers: Trigger<EntityDict, 'essayLabels', BackendRuntimeContext>[] = [
|
||||||
const sequence = count + 1;
|
const sequence = count + 1;
|
||||||
data.sequence = sequence;
|
data.sequence = sequence;
|
||||||
data.meta = {};
|
data.meta = {};
|
||||||
return 1;
|
return 0;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// 在create之前,查询essayId和labelId的组合是否已经存在,如果存在则不允许创建
|
// 在create之前,查询essayId和labelId的组合是否已经存在,如果存在则不允许创建
|
||||||
|
|
@ -83,7 +83,7 @@ const triggers: Trigger<EntityDict, 'essayLabels', BackendRuntimeContext>[] = [
|
||||||
if (count3 > 0) {
|
if (count3 > 0) {
|
||||||
throw new OakUserException('该标签已经关联到文章中');
|
throw new OakUserException('该标签已经关联到文章中');
|
||||||
}
|
}
|
||||||
return 1;
|
return 0;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -143,7 +143,7 @@ const triggers: Trigger<EntityDict, 'essayLabels', BackendRuntimeContext>[] = [
|
||||||
option
|
option
|
||||||
);
|
);
|
||||||
// 将其和当前的seq互换
|
// 将其和当前的seq互换
|
||||||
await context.operate(
|
const opres1 = await context.operate(
|
||||||
'essayLabels',
|
'essayLabels',
|
||||||
{
|
{
|
||||||
id: await generateNewIdAsync(),
|
id: await generateNewIdAsync(),
|
||||||
|
|
@ -157,7 +157,7 @@ const triggers: Trigger<EntityDict, 'essayLabels', BackendRuntimeContext>[] = [
|
||||||
},
|
},
|
||||||
option
|
option
|
||||||
);
|
);
|
||||||
await context.operate(
|
const opres2 = await context.operate(
|
||||||
'essayLabels',
|
'essayLabels',
|
||||||
{
|
{
|
||||||
id: await generateNewIdAsync(),
|
id: await generateNewIdAsync(),
|
||||||
|
|
@ -172,7 +172,10 @@ const triggers: Trigger<EntityDict, 'essayLabels', BackendRuntimeContext>[] = [
|
||||||
option
|
option
|
||||||
);
|
);
|
||||||
|
|
||||||
return 1;
|
return (
|
||||||
|
(opres1.essayLabels?.update || 0) +
|
||||||
|
(opres2.essayLabels?.update || 0)
|
||||||
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -242,7 +245,7 @@ const triggers: Trigger<EntityDict, 'essayLabels', BackendRuntimeContext>[] = [
|
||||||
option
|
option
|
||||||
);
|
);
|
||||||
// 将其和当前的seq互换
|
// 将其和当前的seq互换
|
||||||
await context.operate(
|
const opres1 = await context.operate(
|
||||||
'essayLabels',
|
'essayLabels',
|
||||||
{
|
{
|
||||||
id: await generateNewIdAsync(),
|
id: await generateNewIdAsync(),
|
||||||
|
|
@ -256,7 +259,7 @@ const triggers: Trigger<EntityDict, 'essayLabels', BackendRuntimeContext>[] = [
|
||||||
},
|
},
|
||||||
option
|
option
|
||||||
);
|
);
|
||||||
await context.operate(
|
const opres2 = await context.operate(
|
||||||
'essayLabels',
|
'essayLabels',
|
||||||
{
|
{
|
||||||
id: await generateNewIdAsync(),
|
id: await generateNewIdAsync(),
|
||||||
|
|
@ -270,7 +273,10 @@ const triggers: Trigger<EntityDict, 'essayLabels', BackendRuntimeContext>[] = [
|
||||||
},
|
},
|
||||||
option
|
option
|
||||||
);
|
);
|
||||||
return 1;
|
return (
|
||||||
|
(opres1.essayLabels?.update || 0) +
|
||||||
|
(opres2.essayLabels?.update || 0)
|
||||||
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -291,6 +297,9 @@ const triggers: Trigger<EntityDict, 'essayLabels', BackendRuntimeContext>[] = [
|
||||||
id && nextId,
|
id && nextId,
|
||||||
'id and nextId are required when moving essayLabels'
|
'id and nextId are required when moving essayLabels'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let res = 0;
|
||||||
|
|
||||||
// 查询当前 essayLabel 和目标 essayLabel 的信息
|
// 查询当前 essayLabel 和目标 essayLabel 的信息
|
||||||
const [currentLabel, nextLabel] = await Promise.all([
|
const [currentLabel, nextLabel] = await Promise.all([
|
||||||
context.select(
|
context.select(
|
||||||
|
|
@ -342,7 +351,7 @@ const triggers: Trigger<EntityDict, 'essayLabels', BackendRuntimeContext>[] = [
|
||||||
);
|
);
|
||||||
|
|
||||||
for (const label of affectedLabels) {
|
for (const label of affectedLabels) {
|
||||||
await context.operate(
|
const opres = await context.operate(
|
||||||
'essayLabels',
|
'essayLabels',
|
||||||
{
|
{
|
||||||
id: await generateNewIdAsync(),
|
id: await generateNewIdAsync(),
|
||||||
|
|
@ -352,6 +361,7 @@ const triggers: Trigger<EntityDict, 'essayLabels', BackendRuntimeContext>[] = [
|
||||||
},
|
},
|
||||||
option
|
option
|
||||||
);
|
);
|
||||||
|
res += opres.essayLabels?.update || 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 下移逻辑
|
// 下移逻辑
|
||||||
|
|
@ -371,7 +381,7 @@ const triggers: Trigger<EntityDict, 'essayLabels', BackendRuntimeContext>[] = [
|
||||||
);
|
);
|
||||||
|
|
||||||
for (const label of affectedLabels) {
|
for (const label of affectedLabels) {
|
||||||
await context.operate(
|
const opres = await context.operate(
|
||||||
'essayLabels',
|
'essayLabels',
|
||||||
{
|
{
|
||||||
id: await generateNewIdAsync(),
|
id: await generateNewIdAsync(),
|
||||||
|
|
@ -381,11 +391,13 @@ const triggers: Trigger<EntityDict, 'essayLabels', BackendRuntimeContext>[] = [
|
||||||
},
|
},
|
||||||
option
|
option
|
||||||
);
|
);
|
||||||
|
|
||||||
|
res += opres.essayLabels?.update || 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新当前 essayLabel 的 sequence
|
// 更新当前 essayLabel 的 sequence
|
||||||
await context.operate(
|
const opres = await context.operate(
|
||||||
'essayLabels',
|
'essayLabels',
|
||||||
{
|
{
|
||||||
id: await generateNewIdAsync(),
|
id: await generateNewIdAsync(),
|
||||||
|
|
@ -395,12 +407,14 @@ const triggers: Trigger<EntityDict, 'essayLabels', BackendRuntimeContext>[] = [
|
||||||
},
|
},
|
||||||
option
|
option
|
||||||
);
|
);
|
||||||
|
|
||||||
|
res += opres.essayLabels?.update || 0;
|
||||||
} else {
|
} else {
|
||||||
// 位置相同,无需移动
|
// 位置相同,无需移动
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return res;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -414,6 +428,8 @@ const triggers: Trigger<EntityDict, 'essayLabels', BackendRuntimeContext>[] = [
|
||||||
const { id } = filter as { id: string };
|
const { id } = filter as { id: string };
|
||||||
assert(id, 'id is required when moving essayLabels to first');
|
assert(id, 'id is required when moving essayLabels to first');
|
||||||
|
|
||||||
|
let res = 0;
|
||||||
|
|
||||||
// 查询当前 essayLabel 的信息
|
// 查询当前 essayLabel 的信息
|
||||||
const [currentLabel] = await context.select(
|
const [currentLabel] = await context.select(
|
||||||
'essayLabels',
|
'essayLabels',
|
||||||
|
|
@ -450,7 +466,7 @@ const triggers: Trigger<EntityDict, 'essayLabels', BackendRuntimeContext>[] = [
|
||||||
|
|
||||||
// 更新受影响的 essayLabels
|
// 更新受影响的 essayLabels
|
||||||
for (const label of affectedLabels) {
|
for (const label of affectedLabels) {
|
||||||
await context.operate(
|
const opres = await context.operate(
|
||||||
'essayLabels',
|
'essayLabels',
|
||||||
{
|
{
|
||||||
id: await generateNewIdAsync(),
|
id: await generateNewIdAsync(),
|
||||||
|
|
@ -460,10 +476,11 @@ const triggers: Trigger<EntityDict, 'essayLabels', BackendRuntimeContext>[] = [
|
||||||
},
|
},
|
||||||
option
|
option
|
||||||
);
|
);
|
||||||
|
res += opres.essayLabels?.update || 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将当前 essayLabels 移到第一位
|
// 将当前 essayLabels 移到第一位
|
||||||
await context.operate(
|
const opres = await context.operate(
|
||||||
'essayLabels',
|
'essayLabels',
|
||||||
{
|
{
|
||||||
id: await generateNewIdAsync(),
|
id: await generateNewIdAsync(),
|
||||||
|
|
@ -473,9 +490,10 @@ const triggers: Trigger<EntityDict, 'essayLabels', BackendRuntimeContext>[] = [
|
||||||
},
|
},
|
||||||
option
|
option
|
||||||
);
|
);
|
||||||
|
res += opres.essayLabels?.update || 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return res;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -489,6 +507,8 @@ const triggers: Trigger<EntityDict, 'essayLabels', BackendRuntimeContext>[] = [
|
||||||
const { id } = filter as { id: string };
|
const { id } = filter as { id: string };
|
||||||
assert(id, 'id is required when moving essayLabels to last');
|
assert(id, 'id is required when moving essayLabels to last');
|
||||||
|
|
||||||
|
let res = 0;
|
||||||
|
|
||||||
// 查询当前 essayLabels 的信息
|
// 查询当前 essayLabels 的信息
|
||||||
const [currentLabel] = await context.select(
|
const [currentLabel] = await context.select(
|
||||||
'essayLabels',
|
'essayLabels',
|
||||||
|
|
@ -538,7 +558,7 @@ const triggers: Trigger<EntityDict, 'essayLabels', BackendRuntimeContext>[] = [
|
||||||
|
|
||||||
// 更新受影响的 essayLabels
|
// 更新受影响的 essayLabels
|
||||||
for (const label of affectedLabels) {
|
for (const label of affectedLabels) {
|
||||||
await context.operate(
|
const opres = await context.operate(
|
||||||
'essayLabels',
|
'essayLabels',
|
||||||
{
|
{
|
||||||
id: await generateNewIdAsync(),
|
id: await generateNewIdAsync(),
|
||||||
|
|
@ -548,10 +568,12 @@ const triggers: Trigger<EntityDict, 'essayLabels', BackendRuntimeContext>[] = [
|
||||||
},
|
},
|
||||||
option
|
option
|
||||||
);
|
);
|
||||||
|
|
||||||
|
res += opres.essayLabels?.update || 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将当前 essayLabels 移到最后一位
|
// 将当前 essayLabels 移到最后一位
|
||||||
await context.operate(
|
const opres = await context.operate(
|
||||||
'essayLabels',
|
'essayLabels',
|
||||||
{
|
{
|
||||||
id: await generateNewIdAsync(),
|
id: await generateNewIdAsync(),
|
||||||
|
|
@ -561,9 +583,11 @@ const triggers: Trigger<EntityDict, 'essayLabels', BackendRuntimeContext>[] = [
|
||||||
},
|
},
|
||||||
option
|
option
|
||||||
);
|
);
|
||||||
|
|
||||||
|
res += opres.essayLabels?.update || 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return res;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -575,6 +599,7 @@ const triggers: Trigger<EntityDict, 'essayLabels', BackendRuntimeContext>[] = [
|
||||||
const { filter } = operation;
|
const { filter } = operation;
|
||||||
assert(filter);
|
assert(filter);
|
||||||
|
|
||||||
|
let res = 0;
|
||||||
// 因为删除可能是一个批量操作,filter可以查询到0-n条记录
|
// 因为删除可能是一个批量操作,filter可以查询到0-n条记录
|
||||||
const essayLabels = await context.select(
|
const essayLabels = await context.select(
|
||||||
'essayLabels',
|
'essayLabels',
|
||||||
|
|
@ -609,7 +634,7 @@ const triggers: Trigger<EntityDict, 'essayLabels', BackendRuntimeContext>[] = [
|
||||||
|
|
||||||
// 更新受影响的 essayLabels
|
// 更新受影响的 essayLabels
|
||||||
for (const label of affectedLabels) {
|
for (const label of affectedLabels) {
|
||||||
await context.operate(
|
const opres = await context.operate(
|
||||||
'essayLabels',
|
'essayLabels',
|
||||||
{
|
{
|
||||||
id: await generateNewIdAsync(),
|
id: await generateNewIdAsync(),
|
||||||
|
|
@ -619,9 +644,11 @@ const triggers: Trigger<EntityDict, 'essayLabels', BackendRuntimeContext>[] = [
|
||||||
},
|
},
|
||||||
option
|
option
|
||||||
);
|
);
|
||||||
|
|
||||||
|
res += opres.essayLabels?.update || 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 1;
|
return res;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ const triggers: Trigger<EntityDict, 'label', BackendRuntimeContext>[] = [
|
||||||
const { data } = operation;
|
const { data } = operation;
|
||||||
assert(data && !Array.isArray(data));
|
assert(data && !Array.isArray(data));
|
||||||
data.meta = {};
|
data.meta = {};
|
||||||
return 1;
|
return 0;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// 在执行addToEssay时,将创建essayLabels,将label关联到essay中
|
// 在执行addToEssay时,将创建essayLabels,将label关联到essay中
|
||||||
|
|
@ -57,7 +57,7 @@ const triggers: Trigger<EntityDict, 'label', BackendRuntimeContext>[] = [
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建关联
|
// 创建关联
|
||||||
await context.operate(
|
const opres = await context.operate(
|
||||||
'essayLabels',
|
'essayLabels',
|
||||||
{
|
{
|
||||||
id: await generateNewIdAsync(),
|
id: await generateNewIdAsync(),
|
||||||
|
|
@ -71,7 +71,7 @@ const triggers: Trigger<EntityDict, 'label', BackendRuntimeContext>[] = [
|
||||||
option
|
option
|
||||||
);
|
);
|
||||||
|
|
||||||
return 1;
|
return opres.essayLabels?.create || 0;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ export const essayProjection: EntityDict['essay']['Selection']['data'] = {
|
||||||
name: 1,
|
name: 1,
|
||||||
},
|
},
|
||||||
iState: 1,
|
iState: 1,
|
||||||
isTop: 1,
|
topState: 1,
|
||||||
// 相关labels
|
// 相关labels
|
||||||
essayLabels$essay: {
|
essayLabels$essay: {
|
||||||
$entity: 'essayLabels',
|
$entity: 'essayLabels',
|
||||||
|
|
@ -81,6 +81,18 @@ export const essayProjection: EntityDict['essay']['Selection']['data'] = {
|
||||||
},
|
},
|
||||||
count: 1,
|
count: 1,
|
||||||
},
|
},
|
||||||
|
// 点赞相关的记录
|
||||||
|
like$essay: {
|
||||||
|
$entity: "like",
|
||||||
|
data: {
|
||||||
|
id: 1,
|
||||||
|
user: {
|
||||||
|
id: 1,
|
||||||
|
name: 1,
|
||||||
|
nickname: 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const categoryProjection: EntityDict['category']['Selection']['data'] = {
|
export const categoryProjection: EntityDict['category']['Selection']['data'] = {
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,11 @@
|
||||||
"dom.iterable",
|
"dom.iterable",
|
||||||
"esnext"
|
"esnext"
|
||||||
],
|
],
|
||||||
|
"plugins": [
|
||||||
|
{
|
||||||
|
"name": "typescript-plugin-css-modules",
|
||||||
|
},
|
||||||
|
],
|
||||||
//"outDir": "lib", /* Redirect output structure to the directory. */
|
//"outDir": "lib", /* Redirect output structure to the directory. */
|
||||||
//"rootDir": "src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
//"rootDir": "src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
||||||
"types": [
|
"types": [
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue