├── mock
└── .gitkeep
├── src
├── models
│ ├── .gitkeep
│ ├── ad.js
│ ├── report.js
│ ├── article
│ │ ├── reward.js
│ │ └── user.js
│ ├── software
│ │ ├── group.js
│ │ ├── reward.js
│ │ └── user.js
│ ├── answer
│ │ ├── group-user.js
│ │ ├── reward.js
│ │ └── user.js
│ ├── question
│ │ └── user.js
│ ├── column
│ │ └── member.js
│ ├── path.js
│ ├── doc
│ │ └── version.js
│ └── user
│ │ ├── bank.js
│ │ └── third-account.js
├── pages
│ ├── user
│ │ ├── settings
│ │ │ ├── profile
│ │ │ │ └── index.less
│ │ │ ├── account
│ │ │ │ ├── components
│ │ │ │ │ ├── Path
│ │ │ │ │ │ └── formMap.js
│ │ │ │ │ ├── Email
│ │ │ │ │ │ └── formMap.js
│ │ │ │ │ ├── Mobile
│ │ │ │ │ │ └── formMap.js
│ │ │ │ │ ├── Third
│ │ │ │ │ │ └── index.less
│ │ │ │ │ └── Password
│ │ │ │ │ │ └── formMap.js
│ │ │ │ └── index.less
│ │ │ ├── notifications
│ │ │ │ └── service.js
│ │ │ └── components
│ │ │ │ └── Layout
│ │ │ │ ├── sider.js
│ │ │ │ └── index.js
│ │ ├── dashboard
│ │ │ ├── analytics
│ │ │ │ ├── components
│ │ │ │ │ ├── Content
│ │ │ │ │ │ ├── Chart
│ │ │ │ │ │ │ ├── index.less
│ │ │ │ │ │ │ └── Line.js
│ │ │ │ │ │ ├── DateSelect
│ │ │ │ │ │ │ └── index.less
│ │ │ │ │ │ ├── index.less
│ │ │ │ │ │ └── index.js
│ │ │ │ │ └── Total
│ │ │ │ │ │ └── index.less
│ │ │ │ └── service.js
│ │ │ ├── income
│ │ │ │ ├── components
│ │ │ │ │ ├── Content
│ │ │ │ │ │ ├── Chart
│ │ │ │ │ │ │ ├── index.less
│ │ │ │ │ │ │ └── Line.js
│ │ │ │ │ │ ├── DateSelect
│ │ │ │ │ │ │ └── index.less
│ │ │ │ │ │ ├── index.less
│ │ │ │ │ │ └── index.js
│ │ │ │ │ └── Total
│ │ │ │ │ │ └── index.less
│ │ │ │ └── service.js
│ │ │ ├── history
│ │ │ │ ├── service.js
│ │ │ │ ├── model.js
│ │ │ │ └── index.less
│ │ │ ├── wallet
│ │ │ │ ├── components
│ │ │ │ │ └── Access
│ │ │ │ │ │ ├── index.less
│ │ │ │ │ │ └── Withdraw
│ │ │ │ │ │ └── index.less
│ │ │ │ └── index.js
│ │ │ ├── recent
│ │ │ │ └── service.js
│ │ │ ├── column
│ │ │ │ └── index.less
│ │ │ ├── follows
│ │ │ │ └── index.less
│ │ │ └── components
│ │ │ │ ├── Layout
│ │ │ │ ├── index.js
│ │ │ │ └── Nav
│ │ │ │ │ ├── index.less
│ │ │ │ │ └── index.js
│ │ │ │ └── CardMenu
│ │ │ │ └── index.less
│ │ ├── register
│ │ │ ├── service.js
│ │ │ ├── formMap.js
│ │ │ ├── model.js
│ │ │ └── index.less
│ │ ├── notifications
│ │ │ └── components
│ │ │ │ └── Layout
│ │ │ │ ├── index.js
│ │ │ │ └── sider.js
│ │ ├── login
│ │ │ ├── service.js
│ │ │ ├── formMap.js
│ │ │ └── index.less
│ │ └── locales
│ │ │ └── zh-CN.js
│ ├── path
│ │ ├── components
│ │ │ ├── column
│ │ │ │ └── components
│ │ │ │ │ ├── setting
│ │ │ │ │ ├── index.less
│ │ │ │ │ └── formMap.js
│ │ │ │ │ └── member
│ │ │ │ │ └── index.js
│ │ │ └── user
│ │ │ │ ├── components
│ │ │ │ ├── Column.less
│ │ │ │ └── Activity.less
│ │ │ │ └── menu.js
│ │ ├── services
│ │ │ └── user
│ │ │ │ └── service.js
│ │ └── models
│ │ │ └── user
│ │ │ └── model.js
│ ├── home
│ │ ├── locales
│ │ │ └── zh-CN.js
│ │ ├── service.js
│ │ ├── index.less
│ │ └── components
│ │ │ ├── Writer
│ │ │ └── index.js
│ │ │ └── Answerer
│ │ │ └── index.js
│ ├── yun
│ │ └── locales
│ │ │ └── zh-CN.js
│ ├── Search
│ │ ├── locales
│ │ │ └── zh-CN.js
│ │ ├── service.js
│ │ ├── menus.js
│ │ └── index.less
│ ├── search
│ │ ├── locales
│ │ │ └── zh-CN.js
│ │ ├── service.js
│ │ ├── menus.js
│ │ └── index.less
│ ├── knowledge
│ │ ├── locales
│ │ │ └── zh-CN.js
│ │ └── index.js
│ ├── question
│ │ ├── detail
│ │ │ └── components
│ │ │ │ ├── Related
│ │ │ │ └── index.less
│ │ │ │ ├── Answer
│ │ │ │ ├── index.js
│ │ │ │ └── index.less
│ │ │ │ ├── Comment
│ │ │ │ └── index.less
│ │ │ │ └── Author
│ │ │ │ └── index.less
│ │ ├── components
│ │ │ ├── GroupUser
│ │ │ │ └── index.less
│ │ │ └── HistoryExtra
│ │ │ │ ├── index.less
│ │ │ │ └── index.js
│ │ ├── locales
│ │ │ └── zh-CN.js
│ │ ├── Edit
│ │ │ └── components
│ │ │ │ ├── Reward
│ │ │ │ └── index.less
│ │ │ │ └── Alert
│ │ │ │ ├── index.less
│ │ │ │ └── index.js
│ │ └── edit
│ │ │ └── components
│ │ │ ├── Reward
│ │ │ └── index.less
│ │ │ └── Alert
│ │ │ ├── index.less
│ │ │ └── index.js
│ ├── Column
│ │ ├── locales
│ │ │ └── zh-CN.js
│ │ └── index.less
│ ├── column
│ │ ├── locales
│ │ │ └── zh-CN.js
│ │ ├── apply
│ │ │ ├── index.less
│ │ │ └── formMap.js
│ │ └── index.less
│ ├── Tag
│ │ ├── locales
│ │ │ └── zh-CN.js
│ │ ├── detail
│ │ │ ├── components
│ │ │ │ ├── Intro.js
│ │ │ │ ├── Column.less
│ │ │ │ ├── RelatedArticle
│ │ │ │ │ └── index.less
│ │ │ │ └── RelatedColumn
│ │ │ │ │ └── index.less
│ │ │ ├── index.less
│ │ │ └── menu.js
│ │ └── list
│ │ │ └── index.less
│ ├── tag
│ │ ├── locales
│ │ │ └── zh-CN.js
│ │ ├── detail
│ │ │ ├── components
│ │ │ │ ├── Intro.js
│ │ │ │ ├── Column.less
│ │ │ │ ├── RelatedArticle
│ │ │ │ │ └── index.less
│ │ │ │ └── RelatedColumn
│ │ │ │ │ └── index.less
│ │ │ ├── index.less
│ │ │ └── menu.js
│ │ └── list
│ │ │ └── index.less
│ ├── preview
│ │ ├── service.js
│ │ ├── index.less
│ │ ├── model.js
│ │ └── index.js
│ ├── software
│ │ ├── detail
│ │ │ └── components
│ │ │ │ └── Action
│ │ │ │ ├── index.js
│ │ │ │ └── Delete.js
│ │ ├── edit
│ │ │ └── components
│ │ │ │ ├── Group
│ │ │ │ ├── index.less
│ │ │ │ └── index.js
│ │ │ │ ├── Manage
│ │ │ │ └── index.less
│ │ │ │ └── Setting
│ │ │ │ └── formMap.js
│ │ ├── locales
│ │ │ └── zh-CN.js
│ │ └── index.less
│ ├── article
│ │ ├── Edit
│ │ │ └── components
│ │ │ │ ├── Column
│ │ │ │ └── index.less
│ │ │ │ └── Source
│ │ │ │ └── index.less
│ │ ├── edit
│ │ │ └── components
│ │ │ │ ├── Column
│ │ │ │ └── index.less
│ │ │ │ ├── Source
│ │ │ │ └── index.less
│ │ │ │ └── Setting
│ │ │ │ └── formMap.js
│ │ ├── locales
│ │ │ └── zh-CN.js
│ │ ├── components
│ │ │ ├── HistoryExtra
│ │ │ │ ├── index.less
│ │ │ │ └── index.js
│ │ │ ├── HotTag
│ │ │ │ └── index.js
│ │ │ └── HotColumn
│ │ │ │ └── index.less
│ │ └── detail
│ │ │ └── Related.js
│ ├── Article
│ │ └── locales
│ │ │ └── zh-CN.js
│ ├── Question
│ │ └── locales
│ │ │ └── zh-CN.js
│ ├── 404.js
│ ├── 403.js
│ ├── 500.js
│ ├── document.ejs
│ └── User
│ │ └── locales
│ │ └── zh-CN.js
├── components
│ ├── Editor
│ │ ├── Section
│ │ │ ├── paidcontent
│ │ │ │ ├── SubEditor
│ │ │ │ │ ├── index.js
│ │ │ │ │ └── index.less
│ │ │ │ ├── Setting.js
│ │ │ │ ├── Content
│ │ │ │ │ └── index.js
│ │ │ │ └── index.less
│ │ │ └── index.js
│ │ ├── Plugin
│ │ │ ├── index.js
│ │ │ └── PaidContent.js
│ │ ├── Collab
│ │ │ ├── ot
│ │ │ │ ├── logger
│ │ │ │ │ ├── index.js
│ │ │ │ │ └── logger.js
│ │ │ │ ├── snapshot.js
│ │ │ │ ├── client
│ │ │ │ │ ├── index.js
│ │ │ │ │ └── snapshot-request
│ │ │ │ │ │ ├── snapshot-version-request.js
│ │ │ │ │ │ └── snapshot-timestamp-request.js
│ │ │ │ ├── error.js
│ │ │ │ ├── types.js
│ │ │ │ ├── emitter.js
│ │ │ │ └── util.js
│ │ │ └── constant
│ │ │ │ └── index.js
│ │ └── utils.js
│ ├── Form
│ │ ├── index.less
│ │ ├── WrapItem
│ │ │ ├── Default.less
│ │ │ ├── Capthcha.less
│ │ │ └── index.js
│ │ ├── formContext.js
│ │ ├── Submit.js
│ │ ├── map.less
│ │ └── Tab.js
│ ├── Loading
│ │ ├── Button.less
│ │ ├── index.less
│ │ ├── Button.js
│ │ └── index.js
│ ├── Content
│ │ ├── Question
│ │ │ └── Action
│ │ │ │ ├── index.js
│ │ │ │ ├── Favorite.js
│ │ │ │ └── Delete.js
│ │ ├── index.js
│ │ ├── Article
│ │ │ └── Action
│ │ │ │ ├── index.js
│ │ │ │ ├── Favorite.js
│ │ │ │ └── Delete.js
│ │ └── Answer
│ │ │ └── Action
│ │ │ ├── index.js
│ │ │ ├── Favorite.js
│ │ │ └── Adopt.js
│ ├── Tag
│ │ ├── Selector.less
│ │ ├── Create
│ │ │ └── formMap.js
│ │ ├── Brand
│ │ │ └── index.less
│ │ └── Star
│ │ │ └── index.js
│ ├── User
│ │ ├── Verify
│ │ │ └── formMap.js
│ │ ├── index.js
│ │ ├── Actors
│ │ │ ├── index.less
│ │ │ └── index.js
│ │ ├── Brand
│ │ │ └── index.less
│ │ └── Star
│ │ │ └── index.js
│ ├── Button
│ │ ├── RewardButton
│ │ │ ├── index.js
│ │ │ └── Button
│ │ │ │ └── index.less
│ │ ├── ReportButton
│ │ │ ├── Form
│ │ │ │ ├── index.less
│ │ │ │ └── formMap.js
│ │ │ ├── Modal.less
│ │ │ └── index.js
│ │ ├── FavoriteButton.js
│ │ ├── OpposeButton.js
│ │ ├── ShareButton
│ │ │ └── index.less
│ │ ├── EllipsisButton.js
│ │ ├── AdoptButton.js
│ │ ├── HistoryButton.js
│ │ ├── ReplyButton.js
│ │ ├── EditButton.js
│ │ ├── DeleteButton.js
│ │ ├── CommentButton.js
│ │ ├── BackTopButton.js
│ │ ├── SupportButton.js
│ │ ├── BaseButton.js
│ │ ├── index.less
│ │ └── index.js
│ ├── PaidRead
│ │ ├── index.js
│ │ ├── Purchase
│ │ │ └── index.less
│ │ └── Setting
│ │ │ └── index.less
│ ├── Column
│ │ ├── index.js
│ │ ├── Brand
│ │ │ └── index.less
│ │ └── Star
│ │ │ └── index.js
│ ├── ThirdParty
│ │ ├── index.less
│ │ ├── index.js
│ │ ├── GithubIcon.js
│ │ ├── AlipayIcon.js
│ │ ├── AlipayLogin.js
│ │ └── GithubLogin.js
│ ├── List
│ │ ├── index.js
│ │ ├── Default.js
│ │ └── More.js
│ ├── Header
│ │ ├── Logo.js
│ │ ├── index.js
│ │ ├── Container.js
│ │ ├── Burger
│ │ │ └── index.less
│ │ ├── Search
│ │ │ ├── index.less
│ │ │ └── index.js
│ │ └── User
│ │ │ └── ActionMenu.js
│ ├── Ad
│ │ ├── index.less
│ │ ├── Baidu.js
│ │ └── AdSense.js
│ ├── Footer
│ │ └── index.less
│ ├── Timer
│ │ └── index.js
│ ├── Pay
│ │ └── QrCode
│ │ │ └── index.less
│ ├── AvatarCropper
│ │ ├── ImageCropper.less
│ │ └── index.less
│ ├── Container
│ │ ├── index.less
│ │ ├── Sider.js
│ │ └── Layout.js
│ ├── Exception
│ │ └── index.js
│ └── Comment
│ │ └── Detail.js
├── context
│ ├── index.js
│ └── RouteContext.js
├── services
│ ├── path.js
│ ├── answer
│ │ ├── user.js
│ │ ├── group-user.js
│ │ ├── star.js
│ │ └── comment.js
│ ├── article
│ │ ├── user.js
│ │ ├── star.js
│ │ ├── comment.js
│ │ └── index.js
│ ├── column
│ │ ├── member.js
│ │ ├── star.js
│ │ └── index.js
│ ├── question
│ │ ├── user.js
│ │ ├── star.js
│ │ ├── index.js
│ │ └── comment.js
│ ├── software
│ │ ├── user.js
│ │ ├── group.js
│ │ ├── file.js
│ │ ├── index.js
│ │ └── comment.js
│ ├── user
│ │ ├── oauth.js
│ │ ├── bank.js
│ │ ├── third-account.js
│ │ ├── verify.js
│ │ ├── withdraw.js
│ │ ├── pay.js
│ │ ├── star.js
│ │ └── index.js
│ ├── report.js
│ ├── system
│ │ └── index.js
│ ├── doc
│ │ ├── version.js
│ │ └── index.js
│ ├── tag
│ │ ├── star.js
│ │ └── index.js
│ ├── reward.js
│ ├── notifications.js
│ └── validation.js
├── app.js
├── locales
│ └── zh-CN.js
├── wrappers
│ └── auth.js
├── layouts
│ ├── BasicLayout.js
│ ├── PassportLayout.less
│ └── PassportLayout.js
└── access.js
├── .env
├── .eslintrc
├── dump.rdb
├── .gitattributes
├── .prettierignore
├── .prettierrc
├── jsconfig.json
├── .editorconfig
├── .gitignore
└── config
└── defaultSettings.js
/mock/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/models/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.env:
--------------------------------------------------------------------------------
1 | BROWSER=none
2 | ESLINT=1
3 |
--------------------------------------------------------------------------------
/src/pages/user/settings/profile/index.less:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "eslint-config-umi"
3 | }
4 |
--------------------------------------------------------------------------------
/src/components/Editor/Section/paidcontent/SubEditor/index.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/Editor/Section/paidcontent/SubEditor/index.less:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/pages/path/components/column/components/setting/index.less:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/dump.rdb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/big-camel/itellyou/HEAD/dump.rdb
--------------------------------------------------------------------------------
/src/components/Form/index.less:
--------------------------------------------------------------------------------
1 | .tabs {
2 | text-align: center;
3 | }
4 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/src/pages/home/locales/zh-CN.js:
--------------------------------------------------------------------------------
1 |
2 | export default {
3 | 'home.page.index':"首页"
4 | }
--------------------------------------------------------------------------------
/src/pages/yun/locales/zh-CN.js:
--------------------------------------------------------------------------------
1 | export default {
2 | 'yun.page.index': '云服务',
3 | };
4 |
--------------------------------------------------------------------------------
/src/components/Loading/Button.less:
--------------------------------------------------------------------------------
1 | .default {
2 | width: 100%;
3 | margin: 10px 0;
4 | }
--------------------------------------------------------------------------------
/src/pages/Search/locales/zh-CN.js:
--------------------------------------------------------------------------------
1 | export default {
2 | 'search.page.index': '搜索',
3 | };
4 |
--------------------------------------------------------------------------------
/src/pages/search/locales/zh-CN.js:
--------------------------------------------------------------------------------
1 | export default {
2 | 'search.page.index': '搜索',
3 | };
4 |
--------------------------------------------------------------------------------
/src/context/index.js:
--------------------------------------------------------------------------------
1 | import RouteContext from './RouteContext';
2 |
3 | export { RouteContext };
4 |
--------------------------------------------------------------------------------
/src/pages/knowledge/locales/zh-CN.js:
--------------------------------------------------------------------------------
1 | export default {
2 | 'knowledge.page.index': '知识',
3 | };
4 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | **/*.md
2 | **/*.svg
3 | **/*.ejs
4 | **/*.html
5 | package.json
6 | .umi
7 | .umi-production
8 |
--------------------------------------------------------------------------------
/src/context/RouteContext.js:
--------------------------------------------------------------------------------
1 | import { createContext } from 'react';
2 |
3 | export default createContext({});
4 |
--------------------------------------------------------------------------------
/src/pages/user/dashboard/analytics/components/Content/Chart/index.less:
--------------------------------------------------------------------------------
1 | .chart {
2 | padding: 16px;
3 | }
4 |
--------------------------------------------------------------------------------
/src/pages/user/dashboard/income/components/Content/Chart/index.less:
--------------------------------------------------------------------------------
1 | .chart {
2 | padding: 16px;
3 | }
4 |
--------------------------------------------------------------------------------
/src/components/Editor/Plugin/index.js:
--------------------------------------------------------------------------------
1 | import PaidContent from './PaidContent';
2 |
3 | export { PaidContent };
4 |
--------------------------------------------------------------------------------
/src/components/Editor/Section/index.js:
--------------------------------------------------------------------------------
1 | import PaidContent from './paidcontent';
2 |
3 | export { PaidContent };
4 |
--------------------------------------------------------------------------------
/src/pages/question/detail/components/Related/index.less:
--------------------------------------------------------------------------------
1 | .related-list {
2 | .related-link {
3 | color: #262626;
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/Editor/Collab/ot/logger/index.js:
--------------------------------------------------------------------------------
1 | var Logger = require('./logger');
2 | var logger = new Logger();
3 | module.exports = logger;
4 |
--------------------------------------------------------------------------------
/src/components/Form/WrapItem/Default.less:
--------------------------------------------------------------------------------
1 | .hidden {
2 | :global(.ant-form-item-control-input) {
3 | display: none;
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/src/pages/user/dashboard/income/components/Content/DateSelect/index.less:
--------------------------------------------------------------------------------
1 | .radio-date {
2 | text-align: center;
3 | margin: 16px auto;
4 | }
5 |
--------------------------------------------------------------------------------
/src/components/Form/formContext.js:
--------------------------------------------------------------------------------
1 | import { createContext } from 'react';
2 |
3 | const FormContext = createContext();
4 | export default FormContext;
5 |
--------------------------------------------------------------------------------
/src/pages/user/dashboard/analytics/components/Content/DateSelect/index.less:
--------------------------------------------------------------------------------
1 | .radio-date {
2 | text-align: center;
3 | margin: 16px auto;
4 | }
5 |
--------------------------------------------------------------------------------
/src/components/Content/Question/Action/index.js:
--------------------------------------------------------------------------------
1 | import Favorite from './Favorite';
2 | import Delete from './Delete';
3 |
4 | export { Favorite, Delete };
5 |
--------------------------------------------------------------------------------
/src/components/Tag/Selector.less:
--------------------------------------------------------------------------------
1 | .tag-selector {
2 | flex-wrap: wrap;
3 |
4 | :global(.ant-space-item) {
5 | margin-bottom: 8px;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/User/Verify/formMap.js:
--------------------------------------------------------------------------------
1 | import formMap from '@/components/Form/map';
2 | const { Captcha } = formMap;
3 | export default {
4 | Captcha,
5 | };
6 |
--------------------------------------------------------------------------------
/src/components/Button/RewardButton/index.js:
--------------------------------------------------------------------------------
1 | import RewardButton from './Button';
2 | import RewardPanel from './Panel';
3 |
4 | export { RewardButton, RewardPanel };
5 |
--------------------------------------------------------------------------------
/src/pages/Column/locales/zh-CN.js:
--------------------------------------------------------------------------------
1 | export default {
2 | 'column.page.index': '专栏',
3 | 'column.page.apply': '专栏申请',
4 | 'column.page.detail': '专栏详情',
5 | };
6 |
--------------------------------------------------------------------------------
/src/pages/column/locales/zh-CN.js:
--------------------------------------------------------------------------------
1 | export default {
2 | 'column.page.index': '专栏',
3 | 'column.page.apply': '专栏申请',
4 | 'column.page.detail': '专栏详情',
5 | };
6 |
--------------------------------------------------------------------------------
/src/components/PaidRead/index.js:
--------------------------------------------------------------------------------
1 | import PaidReadSetting from './Setting';
2 | import PaidReadPurchase from './Purchase';
3 |
4 | export { PaidReadSetting, PaidReadPurchase };
5 |
--------------------------------------------------------------------------------
/src/pages/question/components/GroupUser/index.less:
--------------------------------------------------------------------------------
1 | .group-item{
2 | flex: 1 1;
3 | display: flex;
4 | align-items: center;
5 | justify-content: space-between;
6 | }
--------------------------------------------------------------------------------
/src/components/Editor/Section/paidcontent/Setting.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Modal } from 'antd';
3 |
4 | export default () => {
5 | return ;
6 | };
7 |
--------------------------------------------------------------------------------
/src/components/Loading/index.less:
--------------------------------------------------------------------------------
1 | .loading {
2 | padding: 20px;
3 | text-align: center;
4 | display: block;
5 | }
6 |
7 | .icon {
8 | font-size: 16px;
9 | }
10 |
--------------------------------------------------------------------------------
/src/pages/user/dashboard/income/components/Content/index.less:
--------------------------------------------------------------------------------
1 | .card-content {
2 | :global {
3 | .ant-card-body {
4 | padding: 0;
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/pages/user/settings/account/components/Path/formMap.js:
--------------------------------------------------------------------------------
1 | import formMap from '@/components/Form/map';
2 | const { Path } = formMap;
3 |
4 | export default {
5 | Path,
6 | };
7 |
--------------------------------------------------------------------------------
/src/components/Content/index.js:
--------------------------------------------------------------------------------
1 | import Answer from './Answer';
2 | import Article from './Article';
3 | import Question from './Question';
4 |
5 | export { Answer, Article, Question };
6 |
--------------------------------------------------------------------------------
/src/pages/Tag/locales/zh-CN.js:
--------------------------------------------------------------------------------
1 | export default {
2 | 'tag.page.index': '常用标签',
3 | 'tag.page.list': '全部标签',
4 | 'tag.page.edit': '标签编辑',
5 | 'tag.page.detail': '标签详情',
6 | };
7 |
--------------------------------------------------------------------------------
/src/pages/tag/locales/zh-CN.js:
--------------------------------------------------------------------------------
1 | export default {
2 | 'tag.page.index': '常用标签',
3 | 'tag.page.list': '全部标签',
4 | 'tag.page.edit': '标签编辑',
5 | 'tag.page.detail': '标签详情',
6 | };
7 |
--------------------------------------------------------------------------------
/src/pages/user/dashboard/analytics/components/Content/index.less:
--------------------------------------------------------------------------------
1 | .card-content {
2 | :global {
3 | .ant-card-body {
4 | padding: 0;
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/services/path.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function find(params) {
4 | return request('/api/path/find', {
5 | params,
6 | });
7 | }
8 |
--------------------------------------------------------------------------------
/src/pages/Search/service.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function list(params) {
4 | return request(`/api/search`, {
5 | params,
6 | });
7 | }
8 |
--------------------------------------------------------------------------------
/src/pages/preview/service.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function getURL(params) {
4 | return request(`/api/preview`, {
5 | params,
6 | });
7 | }
8 |
--------------------------------------------------------------------------------
/src/pages/search/service.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function list(params) {
4 | return request(`/api/search`, {
5 | params,
6 | });
7 | }
8 |
--------------------------------------------------------------------------------
/src/pages/software/detail/components/Action/index.js:
--------------------------------------------------------------------------------
1 | import Vote from './Vote';
2 | import Comment from './Comment';
3 | import Delete from './Delete';
4 |
5 | export { Vote, Comment, Delete };
6 |
--------------------------------------------------------------------------------
/src/services/answer/user.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function list(params) {
4 | return request(`/api/user/answer`, {
5 | params,
6 | });
7 | }
8 |
--------------------------------------------------------------------------------
/src/services/article/user.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function list(params) {
4 | return request(`/api/user/article`, {
5 | params,
6 | });
7 | }
8 |
--------------------------------------------------------------------------------
/src/services/column/member.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function list(params) {
4 | return request(`/api/column/member`, {
5 | params,
6 | });
7 | }
8 |
--------------------------------------------------------------------------------
/src/services/question/user.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function list(params) {
4 | return request(`/api/user/question`, {
5 | params,
6 | });
7 | }
8 |
--------------------------------------------------------------------------------
/src/services/software/user.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function list(params) {
4 | return request(`/api/user/software`, {
5 | params,
6 | });
7 | }
8 |
--------------------------------------------------------------------------------
/src/services/user/oauth.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export const oauthURL = async ({ type, action }) => {
4 | return request(`/api/oauth/${type}?action=${action}`);
5 | };
6 |
--------------------------------------------------------------------------------
/src/components/Column/index.js:
--------------------------------------------------------------------------------
1 | import ColumnDetail from './Detail';
2 | import ColumnBrand from './Brand';
3 | import ColumnStar from './Star';
4 |
5 | export { ColumnDetail, ColumnBrand, ColumnStar };
6 |
--------------------------------------------------------------------------------
/src/pages/article/Edit/components/Column/index.less:
--------------------------------------------------------------------------------
1 | .column {
2 | :global(.ant-radio-wrapper) {
3 | display: block;
4 | height: 30px;
5 | line-height: 30px;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/pages/article/Edit/components/Source/index.less:
--------------------------------------------------------------------------------
1 | .source {
2 | :global(.ant-radio-wrapper) {
3 | display: block;
4 | height: 30px;
5 | line-height: 30px;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/pages/article/edit/components/Column/index.less:
--------------------------------------------------------------------------------
1 | .column {
2 | :global(.ant-radio-wrapper) {
3 | display: block;
4 | height: 30px;
5 | line-height: 30px;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/pages/article/edit/components/Source/index.less:
--------------------------------------------------------------------------------
1 | .source {
2 | :global(.ant-radio-wrapper) {
3 | display: block;
4 | height: 30px;
5 | line-height: 30px;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/pages/software/edit/components/Group/index.less:
--------------------------------------------------------------------------------
1 | .column {
2 | :global(.ant-radio-wrapper) {
3 | display: block;
4 | height: 30px;
5 | line-height: 30px;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/pages/user/settings/account/components/Email/formMap.js:
--------------------------------------------------------------------------------
1 | import formMap from '@/components/Form/map'
2 | const { Email , Captcha } = formMap
3 | export default {
4 | Email,
5 | Captcha
6 | }
7 |
--------------------------------------------------------------------------------
/src/pages/user/settings/account/components/Mobile/formMap.js:
--------------------------------------------------------------------------------
1 | import formMap from '@/components/Form/map'
2 | const { Mobile , Captcha } = formMap
3 | export default {
4 | Mobile,
5 | Captcha
6 | }
7 |
--------------------------------------------------------------------------------
/src/pages/Article/locales/zh-CN.js:
--------------------------------------------------------------------------------
1 | export default {
2 | 'article.page.new': '新建文章',
3 | 'article.page.edit': '文章编辑',
4 | 'article.page.index': '文章列表',
5 | 'article.page.detail': '文章详情',
6 | };
7 |
--------------------------------------------------------------------------------
/src/pages/article/locales/zh-CN.js:
--------------------------------------------------------------------------------
1 | export default {
2 | 'article.page.new': '新建文章',
3 | 'article.page.edit': '文章编辑',
4 | 'article.page.index': '文章列表',
5 | 'article.page.detail': '文章详情',
6 | };
7 |
--------------------------------------------------------------------------------
/src/pages/path/services/user/service.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function list(params) {
4 | return request(`/api/user/activity`, {
5 | params,
6 | });
7 | }
8 |
--------------------------------------------------------------------------------
/src/pages/user/dashboard/history/service.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function list(params) {
4 | return request(`/api/view/list`, {
5 | params,
6 | });
7 | }
8 |
--------------------------------------------------------------------------------
/src/services/answer/group-user.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function list(params) {
4 | return request(`/api/answer/group-user`, {
5 | params,
6 | });
7 | }
8 |
--------------------------------------------------------------------------------
/src/services/software/group.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function list(params) {
4 | return request(`/api/software/group/list`, {
5 | params,
6 | });
7 | }
8 |
--------------------------------------------------------------------------------
/src/pages/Question/locales/zh-CN.js:
--------------------------------------------------------------------------------
1 | export default {
2 | 'question.page.index': '问答列表',
3 | 'question.page.new': '新建提问',
4 | 'question.page.edit': '提问编辑',
5 | 'question.page.detail': '提问详情',
6 | };
7 |
--------------------------------------------------------------------------------
/src/pages/article/components/HistoryExtra/index.less:
--------------------------------------------------------------------------------
1 | .version-extra {
2 | margin-bottom: 24px;
3 |
4 | .tags {
5 | .tag {
6 | margin-right: 8px;
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/pages/question/components/HistoryExtra/index.less:
--------------------------------------------------------------------------------
1 | .version-extra {
2 | margin-bottom: 24px;
3 |
4 | .tags {
5 | .tag {
6 | margin-right: 8px;
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/pages/question/locales/zh-CN.js:
--------------------------------------------------------------------------------
1 | export default {
2 | 'question.page.index': '问答列表',
3 | 'question.page.new': '新建提问',
4 | 'question.page.edit': '提问编辑',
5 | 'question.page.detail': '提问详情',
6 | };
7 |
--------------------------------------------------------------------------------
/src/pages/software/locales/zh-CN.js:
--------------------------------------------------------------------------------
1 | export default {
2 | 'download.page.index': '下载',
3 | 'software.page.edit': '软件编辑',
4 | 'software.page.new': '新建软件',
5 | 'download.page.detail': '下载详情',
6 | };
7 |
--------------------------------------------------------------------------------
/src/services/report.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request'
2 |
3 | export async function post(params) {
4 | return request(`/api/report/post`,{
5 | method:"POST",
6 | data:params
7 | })
8 | }
9 |
--------------------------------------------------------------------------------
/src/components/Editor/Section/paidcontent/Content/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default () => {
4 | return (
5 |
6 |
7 |
8 | );
9 | };
10 |
--------------------------------------------------------------------------------
/src/pages/Tag/detail/components/Intro.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Editor from '@/components/Editor';
3 |
4 | export default ({ content, html }) => {
5 | return ;
6 | };
7 |
--------------------------------------------------------------------------------
/src/pages/tag/detail/components/Intro.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Editor from '@/components/Editor';
3 |
4 | export default ({ content, html }) => {
5 | return ;
6 | };
7 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "trailingComma": "all",
4 | "printWidth": 100,
5 | "overrides": [
6 | {
7 | "files": ".prettierrc",
8 | "options": { "parser": "json" }
9 | }
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/src/components/Content/Article/Action/index.js:
--------------------------------------------------------------------------------
1 | import Vote from './Vote';
2 | import Favorite from './Favorite';
3 | import Comment from './Comment';
4 | import Delete from './Delete';
5 |
6 | export { Vote, Favorite, Comment, Delete };
7 |
--------------------------------------------------------------------------------
/src/pages/user/register/service.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request'
2 |
3 | export async function register(params) {
4 | return request('/api/user/register',{
5 | method: 'POST',
6 | data: params,
7 | });
8 | }
--------------------------------------------------------------------------------
/src/pages/user/register/formMap.js:
--------------------------------------------------------------------------------
1 | import formMap from '@/components/Form/map'
2 |
3 | const { Name , Mobile , Password , Captcha } = formMap
4 |
5 | export default {
6 | Name,
7 | Password,
8 | Mobile,
9 | Captcha,
10 | }
11 |
--------------------------------------------------------------------------------
/src/pages/preview/index.less:
--------------------------------------------------------------------------------
1 | .preview-container {
2 | margin-top: 0;
3 | height: 100vh;
4 |
5 | iframe {
6 | border: 0;
7 | width: 100%;
8 | height: 100%;
9 | background: none;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/components/Editor/Collab/ot/snapshot.js:
--------------------------------------------------------------------------------
1 | module.exports = Snapshot;
2 | function Snapshot(id, version, type, data, meta) {
3 | this.id = id;
4 | this.v = version;
5 | this.type = type;
6 | this.data = data;
7 | this.m = meta;
8 | }
9 |
--------------------------------------------------------------------------------
/src/pages/question/detail/components/Answer/index.js:
--------------------------------------------------------------------------------
1 | import List from './List';
2 | import View from './View';
3 | import { Answer } from '@/components/Content';
4 |
5 | export default {
6 | List,
7 | View,
8 | Edit: Answer.Edit,
9 | };
10 |
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "emitDecoratorMetadata": true,
4 | "experimentalDecorators": true,
5 | "baseUrl": ".",
6 | "paths": {
7 | "@/*": ["./src/*"]
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/components/ThirdParty/index.less:
--------------------------------------------------------------------------------
1 | .third-icon {
2 | font-size: 28px;
3 | }
4 |
5 | .github {
6 | color: #262626;
7 | }
8 |
9 | .alipay {
10 | color: @primary-color;
11 | }
12 |
13 | .third-link {
14 | display: inline-block;
15 | }
16 |
--------------------------------------------------------------------------------
/src/services/system/index.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function getSetting() {
4 | return request('/api/system/setting');
5 | }
6 |
7 | export async function getLink() {
8 | return request('/api/system/link');
9 | }
10 |
--------------------------------------------------------------------------------
/src/components/ThirdParty/index.js:
--------------------------------------------------------------------------------
1 | import AlipayIcon from './AlipayIcon';
2 | import GithubIcon from './GithubIcon';
3 | import AlipayLogin from './AlipayLogin';
4 | import GithubLogin from './GithubLogin';
5 |
6 | export { AlipayIcon, GithubIcon, GithubLogin, AlipayLogin };
7 |
--------------------------------------------------------------------------------
/src/pages/path/components/user/components/Column.less:
--------------------------------------------------------------------------------
1 | .column {
2 | .info {
3 | padding-left: 48px;
4 |
5 | .status {
6 | margin-top: 12px;
7 | color: #8590a6;
8 | font-size: 12px;
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/pages/question/Edit/components/Reward/index.less:
--------------------------------------------------------------------------------
1 | .reward {
2 | .current {
3 | line-height: 32px;
4 |
5 | strong {
6 | margin: 0 2px;
7 | }
8 | }
9 |
10 | .type {
11 | margin-bottom: 16px;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/pages/question/edit/components/Reward/index.less:
--------------------------------------------------------------------------------
1 | .reward {
2 | .current {
3 | line-height: 32px;
4 |
5 | strong {
6 | margin: 0 2px;
7 | }
8 | }
9 |
10 | .type {
11 | margin-bottom: 16px;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/components/List/index.js:
--------------------------------------------------------------------------------
1 | import Default from './Default'
2 | import PageList from './Page'
3 | import ScrollList from './Scroll'
4 | import MoreList from './More'
5 |
6 | export default Default
7 |
8 | export {
9 | PageList,
10 | ScrollList,
11 | MoreList
12 | }
--------------------------------------------------------------------------------
/src/components/Editor/Collab/ot/client/index.js:
--------------------------------------------------------------------------------
1 | exports.Connection = require('./connection');
2 | exports.Doc = require('./doc');
3 | exports.Error = require('../error');
4 | exports.Query = require('./query');
5 | exports.types = require('../types');
6 | exports.logger = require('../logger');
7 |
--------------------------------------------------------------------------------
/src/components/Editor/Collab/ot/error.js:
--------------------------------------------------------------------------------
1 | var makeError = require('make-error');
2 |
3 | function ShareDBError(code, message) {
4 | ShareDBError.super.call(this, message);
5 | this.code = code;
6 | }
7 |
8 | makeError(ShareDBError);
9 |
10 | module.exports = ShareDBError;
11 |
--------------------------------------------------------------------------------
/src/components/User/index.js:
--------------------------------------------------------------------------------
1 | import UserAuthor from './Author';
2 | import UserBrand from './Brand';
3 | import UserVerify from './Verify';
4 | import UserStar from './Star';
5 | import UserActors from './Actors';
6 |
7 | export { UserAuthor, UserBrand, UserVerify, UserStar, UserActors };
8 |
--------------------------------------------------------------------------------
/src/services/software/file.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function recommend({ softwareId, fileId, ...params }) {
4 | return request(`/api/software/${softwareId}/file/${fileId}/recommend`, {
5 | data: params,
6 | method: 'POST',
7 | });
8 | }
9 |
--------------------------------------------------------------------------------
/src/components/Form/WrapItem/Capthcha.less:
--------------------------------------------------------------------------------
1 | .capthcha-item {
2 | display: flex;
3 |
4 | .input {
5 | flex: 1 1;
6 | }
7 |
8 | .btn {
9 | position: relative;
10 | min-width: 120px;
11 | margin-left: 8px;
12 | font-size: 14px;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/components/Form/WrapItem/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Capthcha from './Capthcha';
3 | import Default from './Default';
4 |
5 | export default ({ type, tabUtil, ...props }) => {
6 | if (type === 'Captcha') return ;
7 | return ;
8 | };
9 |
--------------------------------------------------------------------------------
/src/pages/user/settings/account/components/Third/index.less:
--------------------------------------------------------------------------------
1 | .third-warpper {
2 | :global {
3 | .ant-card {
4 | > .ant-card-body {
5 | display: block;
6 | }
7 | }
8 | }
9 |
10 | .content {
11 | margin-top: 24px;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/components/Header/Logo.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import logo from '@/assets/logo.svg'
3 | import styles from './index.less'
4 |
5 | export default () => {
6 | return (
7 |
8 |

9 |
10 | )
11 | }
--------------------------------------------------------------------------------
/src/models/ad.js:
--------------------------------------------------------------------------------
1 | export default {
2 | namespace: 'ad',
3 |
4 | state: {},
5 | effects: {},
6 | reducers: {
7 | setAd(state, { payload }) {
8 | return {
9 | ...state,
10 | detail: { ...payload },
11 | };
12 | },
13 | },
14 | };
15 |
--------------------------------------------------------------------------------
/src/services/user/bank.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function info(params) {
4 | return request(`/api/bank`, {
5 | params,
6 | });
7 | }
8 |
9 | export async function log(params) {
10 | return request(`/api/bank/log`, {
11 | params,
12 | });
13 | }
14 |
--------------------------------------------------------------------------------
/src/components/Button/ReportButton/Form/index.less:
--------------------------------------------------------------------------------
1 | .form {
2 |
3 | .footer {
4 | display: flex;
5 | justify-content: space-between;
6 |
7 | button{
8 | width: 100%;
9 | }
10 |
11 | button:first-child{
12 | margin-right: 16px;
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/src/components/Editor/Collab/ot/types.js:
--------------------------------------------------------------------------------
1 | exports.defaultType = require('ot-json0').type;
2 |
3 | exports.map = {};
4 |
5 | exports.register = function(type) {
6 | if (type.name) exports.map[type.name] = type;
7 | if (type.uri) exports.map[type.uri] = type;
8 | };
9 |
10 | exports.register(exports.defaultType);
11 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_style = space
6 | indent_size = 4
7 | end_of_line = lf
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = true
11 |
12 | [*.md]
13 | trim_trailing_whitespace = false
14 |
15 | [Makefile]
16 | indent_style = tab
17 |
--------------------------------------------------------------------------------
/src/components/ThirdParty/GithubIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import classNames from 'classnames';
3 | import { GithubOutlined } from '@ant-design/icons';
4 | import styles from './index.less';
5 |
6 | export default () => {
7 | return ;
8 | };
9 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /npm-debug.log*
6 | /yarn-error.log
7 | /yarn.lock
8 | /package-lock.json
9 |
10 | # production
11 | /dist
12 |
13 | # misc
14 | .DS_Store
15 |
16 | # umi
17 | .umi
18 | .umi-production
19 |
--------------------------------------------------------------------------------
/src/components/Header/index.js:
--------------------------------------------------------------------------------
1 | import Default from './Default';
2 | import HeaderLogo from './Logo';
3 | import HeaderSearch from './Search';
4 | import HeaderUser from './User';
5 | import HeaderContainer from './Container';
6 |
7 | export default Default;
8 |
9 | export { HeaderLogo, HeaderSearch, HeaderUser, HeaderContainer };
10 |
--------------------------------------------------------------------------------
/src/components/User/Actors/index.less:
--------------------------------------------------------------------------------
1 | .user-actors {
2 | .user-author {
3 | .user-author-name {
4 | font-size: 14px;
5 | }
6 | }
7 |
8 | .user-actors-authors {
9 | display: flex;
10 |
11 | .user-actors-item {
12 | display: flex;
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/pages/question/detail/components/Comment/index.less:
--------------------------------------------------------------------------------
1 | .modal-warpper{
2 |
3 | :global(.ant-modal-body){
4 | padding: 0;
5 | }
6 |
7 | .modal-content{
8 | .modal-comment-list{
9 | margin-top: 0;
10 | border: 0 none;
11 | box-shadow: none;
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/src/components/Editor/Collab/ot/emitter.js:
--------------------------------------------------------------------------------
1 | var EventEmitter = require('events').EventEmitter;
2 |
3 | exports.EventEmitter = EventEmitter;
4 | exports.mixin = mixin;
5 |
6 | function mixin(Constructor) {
7 | for (var key in EventEmitter.prototype) {
8 | Constructor.prototype[key] = EventEmitter.prototype[key];
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/pages/user/dashboard/wallet/components/Access/index.less:
--------------------------------------------------------------------------------
1 | .warpper {
2 | margin-bottom: 20px;
3 |
4 | .body {
5 | display: flex;
6 | justify-content: space-between;
7 |
8 | .action {
9 | :global(.ant-btn) {
10 | width: 100px;
11 | }
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/app.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { ConfigProvider } from 'antd';
3 | import locale from 'antd/es/locale/zh_CN';
4 |
5 | export const rootContainer = (container) => {
6 | return (
7 |
8 | {container}
9 |
10 | );
11 | };
12 |
--------------------------------------------------------------------------------
/src/pages/user/settings/notifications/service.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request'
2 |
3 | export async function list() {
4 | return request('/api/notifications/settings')
5 | }
6 |
7 | export async function set(params) {
8 | return request('/api/notifications/settings',{
9 | method: 'PUT',
10 | data:params
11 | })
12 | }
--------------------------------------------------------------------------------
/src/models/report.js:
--------------------------------------------------------------------------------
1 | import { post } from '@/services/report';
2 | export default {
3 | namespace: 'report',
4 |
5 | state: {},
6 | effects: {
7 | *post({ payload }, { call, put }) {
8 | const response = yield call(post, payload);
9 | return response;
10 | },
11 | },
12 | reducers: {},
13 | };
14 |
--------------------------------------------------------------------------------
/src/pages/user/register/model.js:
--------------------------------------------------------------------------------
1 |
2 | import { register } from './service'
3 |
4 | export default {
5 | namespace: 'register',
6 |
7 | state: {
8 | },
9 |
10 | effects: {
11 | *submit({ payload }, { call }){
12 | const response = yield call(register,payload)
13 | return response
14 | },
15 | }
16 | }
--------------------------------------------------------------------------------
/src/pages/404.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Exception from '@/components/Exception';
3 |
4 | const NotFound = () => {
5 | return ;
6 | };
7 |
8 | NotFound.getInitialProps = async ({ isServer, store }) => {
9 | const { getState } = store;
10 |
11 | if (isServer) return getState();
12 | };
13 |
14 | export default NotFound;
15 |
--------------------------------------------------------------------------------
/src/services/user/third-account.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function find(params) {
4 | return request(`/api/third_account`, {
5 | params,
6 | });
7 | }
8 |
9 | export async function del(params) {
10 | return request(`/api/third_account`, {
11 | method: 'DELETE',
12 | params,
13 | });
14 | }
15 |
--------------------------------------------------------------------------------
/src/components/Button/RewardButton/Button/index.less:
--------------------------------------------------------------------------------
1 | .reward-warpper {
2 | text-align: center;
3 | margin: 16px 0;
4 |
5 | .reward-desc {
6 | font-weight: 500;
7 | }
8 |
9 | .reward-btn {
10 | color: @primary-color;
11 | cursor: pointer;
12 | }
13 |
14 | .reward-list {
15 | line-height: 1;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/pages/403.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Exception from '@/components/Exception';
3 |
4 | const NotAccess = () => {
5 | return ;
6 | };
7 |
8 | NotAccess.getInitialProps = async ({ isServer, store }) => {
9 | const { getState } = store;
10 |
11 | if (isServer) return getState();
12 | };
13 |
14 | export default NotAccess;
15 |
--------------------------------------------------------------------------------
/src/pages/user/dashboard/recent/service.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function draft(params) {
4 | return request(`/api/user/draft`, {
5 | params,
6 | });
7 | }
8 |
9 | export async function del(params) {
10 | return request(`/api/user/draft`, {
11 | method: 'DELETE',
12 | data: params,
13 | });
14 | }
15 |
--------------------------------------------------------------------------------
/config/defaultSettings.js:
--------------------------------------------------------------------------------
1 | const { NODE_ENV } = process.env;
2 | export default {
3 | primaryColor: '#347EFF',
4 | title: 'ITELLYOU,我告诉你',
5 | defaultAvatar: 'https://cdn-object.aomao.com/avatar/default.png',
6 | ws:
7 | NODE_ENV === 'production'
8 | ? 'wss://www.aomao.com/api/websocket'
9 | : 'ws://localhost:8082/websocket',
10 | };
11 |
--------------------------------------------------------------------------------
/src/components/Content/Answer/Action/index.js:
--------------------------------------------------------------------------------
1 | import Vote from './Vote';
2 | import Favorite from './Favorite';
3 | import Comment from './Comment';
4 | import Adopt from './Adopt';
5 | import Delete from './Delete';
6 | import Edit from './Edit';
7 |
8 | export default {
9 | Edit,
10 | Comment,
11 | };
12 |
13 | export { Vote, Favorite, Comment, Adopt, Delete, Edit };
14 |
--------------------------------------------------------------------------------
/src/pages/Tag/detail/index.less:
--------------------------------------------------------------------------------
1 | .layout {
2 | .header {
3 | padding: 0;
4 | margin-bottom: 24px;
5 |
6 | .description {
7 | margin-bottom: 16px;
8 | }
9 | }
10 |
11 | .body {
12 | :global {
13 | .ant-card-head-title {
14 | padding: 0;
15 | }
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/pages/question/Edit/components/Alert/index.less:
--------------------------------------------------------------------------------
1 | .alert {
2 | background: #f9fbfb;
3 |
4 | .message {
5 | font-size: 12px;
6 |
7 | .title {
8 | font-size: 14px;
9 | }
10 |
11 | .item {
12 | color: #595959;
13 | line-height: 12px;
14 | margin-bottom: 8px;
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/pages/question/edit/components/Alert/index.less:
--------------------------------------------------------------------------------
1 | .alert {
2 | background: #f9fbfb;
3 |
4 | .message {
5 | font-size: 12px;
6 |
7 | .title {
8 | font-size: 14px;
9 | }
10 |
11 | .item {
12 | color: #595959;
13 | line-height: 12px;
14 | margin-bottom: 8px;
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/pages/tag/detail/index.less:
--------------------------------------------------------------------------------
1 | .layout {
2 | .header {
3 | padding: 0;
4 | margin-bottom: 24px;
5 |
6 | .description {
7 | margin-bottom: 16px;
8 | }
9 | }
10 |
11 | .body {
12 | :global {
13 | .ant-card-head-title {
14 | padding: 0;
15 | }
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/components/Form/Submit.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Button, Form } from 'antd';
3 |
4 | const SubmitButton = ({ className, noStyle, ...rest }) => {
5 | return (
6 |
7 |
8 |
9 | );
10 | };
11 |
12 | export default SubmitButton;
13 |
--------------------------------------------------------------------------------
/src/pages/user/dashboard/income/service.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function searchByList(params) {
4 | return request(`/api/statistics/income/search/list`, {
5 | params,
6 | });
7 | }
8 |
9 | export async function searchByTotal(params) {
10 | return request(`/api/statistics/income/search/total`, {
11 | params,
12 | });
13 | }
14 |
--------------------------------------------------------------------------------
/src/components/Button/FavoriteButton.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import BaseButton from './BaseButton';
3 | import { StarOutlined } from '@ant-design/icons';
4 |
5 | function FavoriteButton({ children, ...props }) {
6 | return (
7 | } {...props}>
8 | {children}
9 |
10 | );
11 | }
12 | export default FavoriteButton;
13 |
--------------------------------------------------------------------------------
/src/components/Button/OpposeButton.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import BaseButton from './BaseButton';
3 | import { DislikeOutlined } from '@ant-design/icons';
4 |
5 | function OpposeButton({ children, ...props }) {
6 | return (
7 | }>
8 | {children}
9 |
10 | );
11 | }
12 | export default OpposeButton;
13 |
--------------------------------------------------------------------------------
/src/components/Button/ShareButton/index.less:
--------------------------------------------------------------------------------
1 | :global(.ant-menu-item).expand-qrcode {
2 | height: auto !important;
3 |
4 | span:last-child {
5 | display: block;
6 |
7 | .title {
8 | position: absolute;
9 | top: 0;
10 | left: 40px;
11 | }
12 | }
13 |
14 | &:hover {
15 | background: transparent !important;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/pages/article/edit/components/Setting/formMap.js:
--------------------------------------------------------------------------------
1 | import { Input } from 'antd';
2 |
3 | export default {
4 | Cover: {
5 | props: {
6 | type: 'hidden',
7 | },
8 | },
9 | Desc: {
10 | component: Input.TextArea,
11 | props: {
12 | autoSize: { minRows: 3, maxRows: 6 },
13 | maxLength: 200,
14 | },
15 | },
16 | };
17 |
--------------------------------------------------------------------------------
/src/pages/user/settings/components/Layout/sider.js:
--------------------------------------------------------------------------------
1 | export default [
2 | {
3 | key:"profile",
4 | title:"个人信息",
5 | to:"/settings/profile"
6 | },
7 | {
8 | key:"account",
9 | title:"账户管理",
10 | to:"/settings/account"
11 | },
12 | {
13 | key:"notifications",
14 | title:"消息管理",
15 | to:"/settings/notifications"
16 | }
17 | ]
--------------------------------------------------------------------------------
/src/services/user/verify.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function mobile(params) {
4 | return request('/api/user/verify/mobile', {
5 | method: 'POST',
6 | data: params,
7 | });
8 | }
9 |
10 | export async function email(params) {
11 | return request('/api/user/verify/email', {
12 | method: 'POST',
13 | data: params,
14 | });
15 | }
16 |
--------------------------------------------------------------------------------
/src/components/Button/EllipsisButton.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import BaseButton from './BaseButton';
3 | import { EllipsisOutlined } from '@ant-design/icons';
4 |
5 | function EllipsisButton({ children, ...props }) {
6 | return (
7 | }>
8 | {children}
9 |
10 | );
11 | }
12 | export default EllipsisButton;
13 |
--------------------------------------------------------------------------------
/src/pages/path/components/column/components/setting/formMap.js:
--------------------------------------------------------------------------------
1 | import formApplyMap from '@/pages/column/apply/formMap';
2 | import formMap from '@/components/Form/map';
3 | const { Name, Desc } = formApplyMap;
4 | const { Path } = formMap;
5 |
6 | export default {
7 | Name,
8 | Avatar: {
9 | props: {
10 | type: 'hidden',
11 | },
12 | },
13 | Desc,
14 | Path,
15 | };
16 |
--------------------------------------------------------------------------------
/src/pages/user/dashboard/column/index.less:
--------------------------------------------------------------------------------
1 | .column-title {
2 | display: flex;
3 |
4 | .avatar {
5 | margin-right: 16px;
6 | margin-top: 4px;
7 | }
8 |
9 | .content {
10 | > a {
11 | color: #262626;
12 | font-weight: 700;
13 | }
14 |
15 | > p {
16 | color: #595959;
17 | margin: 0;
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/pages/user/dashboard/follows/index.less:
--------------------------------------------------------------------------------
1 | .column-title {
2 | display: flex;
3 |
4 | .avatar {
5 | margin-right: 16px;
6 | margin-top: 4px;
7 | }
8 |
9 | .content {
10 | > a {
11 | color: #262626;
12 | font-weight: 700;
13 | }
14 |
15 | > p {
16 | color: #595959;
17 | margin: 0;
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/components/Ad/index.less:
--------------------------------------------------------------------------------
1 | .auto {
2 | min-width: 100px;
3 | overflow: hidden;
4 | }
5 |
6 | .rectangle {
7 | width: 690px;
8 | height: 280px;
9 | overflow: hidden;
10 | }
11 |
12 | .square {
13 | width: 292px;
14 | height: 292px;
15 | overflow: hidden;
16 | }
17 |
18 | .mobile {
19 | min-width: 200px;
20 | width: 100%;
21 | max-width: 100%;
22 | overflow: hidden;
23 | }
24 |
--------------------------------------------------------------------------------
/src/components/ThirdParty/AlipayIcon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import classNames from 'classnames';
3 | import { AlipayCircleOutlined } from '@ant-design/icons';
4 | import styles from './index.less';
5 |
6 | export default props => {
7 | return (
8 |
12 | );
13 | };
14 |
--------------------------------------------------------------------------------
/src/services/doc/version.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function list({ type, id }) {
4 | return request(`/api/${type}/${id}/version`);
5 | }
6 |
7 | export async function find({ type, id, version_id }) {
8 | return request(`/api/${type}/${id}/version/${version_id}`);
9 | }
10 |
11 | export async function diff({ type, id, str }) {
12 | return request(`/api/${type}/${id}/version/${str}`);
13 | }
14 |
--------------------------------------------------------------------------------
/src/pages/column/apply/index.less:
--------------------------------------------------------------------------------
1 | .container {
2 | width: 680px;
3 |
4 | .description {
5 | border-bottom: 1px solid #f0f0f0;
6 | padding-bottom: 40px;
7 | margin-bottom: 40px;
8 |
9 | > h4 {
10 | font-size: 16px;
11 | margin: 16px 0;
12 | }
13 | }
14 | }
15 |
16 | @media only screen and (max-width: 575px) {
17 | .container {
18 | width: 100%;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/pages/user/settings/account/index.less:
--------------------------------------------------------------------------------
1 | .settings-form {
2 | :global {
3 | .ant-card-body > .ant-card {
4 | margin-bottom: 24px;
5 | > .ant-card-body {
6 | display: flex;
7 | align-items: center;
8 |
9 | .ant-card-meta {
10 | margin: 0;
11 | flex: 1;
12 | }
13 | }
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/components/Button/AdoptButton.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import BaseButton from './BaseButton';
3 | import { CheckCircleOutlined } from '@ant-design/icons';
4 |
5 | function AdoptButton({ children, active, ...props }) {
6 | return (
7 | } {...props}>
8 | {children}
9 |
10 | );
11 | }
12 | export default AdoptButton;
13 |
--------------------------------------------------------------------------------
/src/pages/software/edit/components/Manage/index.less:
--------------------------------------------------------------------------------
1 | .software-release {
2 | .software-updater:global(.ant-collapse) {
3 | :global {
4 | .ant-collapse-header {
5 | padding-left: 24px;
6 | .anticon {
7 | left: 0;
8 | }
9 | }
10 | .ant-collapse-content-box {
11 | padding: 0;
12 | }
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/components/ThirdParty/AlipayLogin.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Tooltip } from 'antd';
3 | import AlipayIcon from './AlipayIcon';
4 | import styles from './index.less';
5 |
6 | export default () => {
7 | return (
8 |
9 |
10 |
11 |
12 |
13 | );
14 | };
15 |
--------------------------------------------------------------------------------
/src/pages/user/dashboard/income/components/Content/Chart/Line.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { dynamic } from 'umi';
3 | import Loading from '@/components/Loading';
4 |
5 | export default dynamic({
6 | loader: async () => {
7 | const { Line } = await import(
8 | /* webpackChunkName: "@ant-design-charts" */ '@ant-design/charts'
9 | );
10 | return Line;
11 | },
12 | loading: () => ,
13 | });
14 |
--------------------------------------------------------------------------------
/src/components/ThirdParty/GithubLogin.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Tooltip } from 'antd';
3 | import GithubIcon from './GithubIcon';
4 | import styles from './index.less';
5 |
6 | export default () => {
7 | return (
8 |
9 |
10 |
11 |
12 |
13 | );
14 | };
15 |
--------------------------------------------------------------------------------
/src/pages/user/dashboard/analytics/components/Content/Chart/Line.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { dynamic } from 'umi';
3 | import Loading from '@/components/Loading';
4 |
5 | export default dynamic({
6 | loader: async () => {
7 | const { Line } = await import(
8 | /* webpackChunkName: "@ant-design-charts" */ '@ant-design/charts'
9 | );
10 | return Line;
11 | },
12 | loading: () => ,
13 | });
14 |
--------------------------------------------------------------------------------
/src/components/PaidRead/Purchase/index.less:
--------------------------------------------------------------------------------
1 | .purchase-layout {
2 | font-size: 14px;
3 | text-align: center;
4 | position: relative;
5 | margin-bottom: 6px;
6 | padding-bottom: 24px;
7 |
8 | .purchase-mask {
9 | height: 130px;
10 | margin-top: -130px;
11 | margin-bottom: 20px;
12 | background: linear-gradient(hsla(0, 0%, 100%, 0.2), #fff);
13 | }
14 |
15 | .purchase-btn {
16 | font-weight: 500;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/pages/home/service.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function recommends(params) {
4 | return request(`/api/explore/recommends`, {
5 | params,
6 | });
7 | }
8 |
9 | export async function writer(params) {
10 | return request(`/api/explore/writer`, {
11 | params,
12 | });
13 | }
14 |
15 | export async function answerer(params) {
16 | return request(`/api/explore/answerer`, {
17 | params,
18 | });
19 | }
20 |
--------------------------------------------------------------------------------
/src/components/Footer/index.less:
--------------------------------------------------------------------------------
1 | .footer {
2 | color: #262626;
3 | font-size: 12px;
4 | padding: 24px 0;
5 |
6 | a {
7 | color: #8c8c8c;
8 | }
9 |
10 | .copyright {
11 | text-align: center;
12 |
13 | > p {
14 | margin: 0;
15 | }
16 | }
17 |
18 | .links {
19 | text-align: center;
20 | padding: 16px 0;
21 |
22 | a {
23 | color: @primary-color;
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/components/Form/map.less:
--------------------------------------------------------------------------------
1 | form {
2 | .help-body {
3 | line-height: 1;
4 | overflow: hidden;
5 |
6 | p {
7 | font-size: 14px;
8 | line-height: 18px;
9 | margin: 8px 0 8px;
10 | color: #000000;
11 | }
12 |
13 | .icon {
14 | color: #a4d3ee;
15 | margin-right: 8px;
16 | }
17 |
18 | .icon.correct {
19 | color: #76ee00;
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/components/Loading/Button.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Button } from 'antd'
3 | import styles from './Button.less'
4 |
5 | export default ({ text , loading , onClick , ...props }) => {
6 | text = text || "加载更多"
7 | onClick = onClick || function(){}
8 | return
19 | }
--------------------------------------------------------------------------------
/src/services/user/withdraw.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function config(params) {
4 | return request(`/api/withdraw/config`, {
5 | params,
6 | });
7 | }
8 |
9 | export async function post(params) {
10 | return request(`/api/withdraw`, {
11 | method: 'POST',
12 | data: params,
13 | });
14 | }
15 |
16 | export async function log(params) {
17 | return request(`/api/withdraw/log`, {
18 | params,
19 | });
20 | }
21 |
--------------------------------------------------------------------------------
/src/pages/500.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Exception from '@/components/Exception';
3 |
4 | const PageException = ({ location: { query } }) => {
5 | const msg = query.m;
6 | const title = query.t;
7 | return ;
8 | };
9 |
10 | PageException.getInitialProps = async ({ isServer, store }) => {
11 | const { getState } = store;
12 |
13 | if (isServer) return getState();
14 | };
15 |
16 | export default PageException;
17 |
--------------------------------------------------------------------------------
/src/pages/software/index.less:
--------------------------------------------------------------------------------
1 | .software-menu:global(.ant-menu) {
2 | border: 0 none;
3 |
4 | :global {
5 | li.ant-menu-item {
6 | margin-bottom: 0;
7 | border-right: 3px solid transparent;
8 | }
9 |
10 | li.ant-menu-item:hover {
11 | border-right-color: @primary-color;
12 | background-color: #f0f8ff;
13 | }
14 | }
15 | }
16 |
17 | .item-card {
18 | .title a {
19 | color: #262626;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/services/user/pay.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function alipayPrecreate(params) {
4 | return request(`/api/pay/alipay`, {
5 | method: 'POST',
6 | data: params,
7 | });
8 | }
9 |
10 | export async function alipayQuery(params) {
11 | return request(`/api/pay/alipay`, {
12 | params,
13 | });
14 | }
15 |
16 | export async function log(params) {
17 | return request(`/api/pay/log`, {
18 | params,
19 | });
20 | }
21 |
--------------------------------------------------------------------------------
/src/components/Editor/Section/paidcontent/index.less:
--------------------------------------------------------------------------------
1 | .itellyou-paidcontent {
2 | border-radius: 8px;
3 | background-color: rgb(246, 246, 247);
4 | cursor: default;
5 | border: 1px solid rgba(17, 31, 44, 0);
6 | padding: 12px;
7 | position: relative;
8 |
9 | .sub-editor {
10 | position: absolute;
11 | background: #fff;
12 | top: 1px;
13 | left: 1px;
14 | width: 100%;
15 | cursor: text;
16 | min-height: 60px;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/components/Button/ReportButton/Form/formMap.js:
--------------------------------------------------------------------------------
1 | import { Input } from 'antd';
2 |
3 | export default {
4 | Desc: {
5 | component: Input.TextArea,
6 | props: {
7 | autoSize: { minRows: 5, maxRows: 20 },
8 | maxLength: 500,
9 | placeholder: '举报原因(字数不多于 500)',
10 | },
11 | rules: [
12 | {
13 | required: true,
14 | message: '请输入举报原因,(字数不多于 500)',
15 | },
16 | ],
17 | },
18 | };
19 |
--------------------------------------------------------------------------------
/src/pages/question/detail/components/Answer/index.less:
--------------------------------------------------------------------------------
1 | .answer-title {
2 | display: inline-block;
3 | font-size: 15px;
4 | font-weight: 600;
5 | color: #1a1a1a;
6 | margin-bottom: 0;
7 | }
8 |
9 | .editor-warpper {
10 | .footer {
11 | display: flex;
12 |
13 | .status {
14 | margin-right: auto;
15 | }
16 |
17 | .action {
18 | display: flex;
19 | }
20 | }
21 | }
22 |
23 | .adopted-card {
24 | margin-bottom: 8px;
25 | }
26 |
--------------------------------------------------------------------------------
/src/components/PaidRead/Setting/index.less:
--------------------------------------------------------------------------------
1 | .paid-setting {
2 | margin-left: 24px;
3 |
4 | > div {
5 | margin-bottom: 1em;
6 |
7 | .desc {
8 | color: #888888;
9 | }
10 |
11 | .paid-value,
12 | .paid-type {
13 | width: 120px;
14 | }
15 | }
16 | }
17 |
18 | .scale-setting {
19 | margin-top: 1em;
20 | padding-top: 1em;
21 | border-top: 1px solid #fafafa;
22 |
23 | :global(.ant-slider) {
24 | margin: 0;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/pages/home/index.less:
--------------------------------------------------------------------------------
1 | .home-carousel {
2 | border-radius: 3px;
3 | overflow: hidden;
4 | :global(.ant-card-body) {
5 | padding: 0;
6 | }
7 | }
8 |
9 | @media only screen and (max-width: 575px) {
10 | .recommends {
11 | :global(.ant-card-body) {
12 | padding: 16px;
13 | }
14 | }
15 | }
16 |
17 | .recruit-card {
18 | :global(.ant-card-body) {
19 | padding: 6px 10px;
20 | }
21 |
22 | p {
23 | margin-bottom: 6px;
24 | line-height: 24px;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/components/Button/HistoryButton.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import BaseButton from './BaseButton';
3 | import { HistoryOutlined } from '@ant-design/icons';
4 |
5 | export default ({ children, onlyIcon, text, ...props }) => {
6 | text = text || '历史版本';
7 | const renderContent = () => {
8 | if (children) return children;
9 | return text;
10 | };
11 |
12 | return (
13 | } {...props}>
14 | {!onlyIcon && renderContent()}
15 |
16 | );
17 | };
18 |
--------------------------------------------------------------------------------
/src/components/Button/ReplyButton.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import BaseButton from './BaseButton';
3 | import { RollbackOutlined } from '@ant-design/icons';
4 |
5 | function ReplyButton({ text, children, ...props }) {
6 | text = text || '回复';
7 | const renderContent = () => {
8 | if (children) return children;
9 | return text;
10 | };
11 | return (
12 | } {...props}>
13 | {renderContent()}
14 |
15 | );
16 | }
17 | export default ReplyButton;
18 |
--------------------------------------------------------------------------------
/src/pages/Search/menus.js:
--------------------------------------------------------------------------------
1 | export default [
2 | {
3 | key: 'all',
4 | title: '全部',
5 | },
6 | {
7 | key: 'question',
8 | title: '问题',
9 | },
10 | {
11 | key: 'answer',
12 | title: '回答',
13 | },
14 | {
15 | key: 'article',
16 | title: '文章',
17 | },
18 | {
19 | key: 'column',
20 | title: '专栏',
21 | },
22 | {
23 | key: 'tag',
24 | title: '标签',
25 | },
26 | {
27 | key: 'user',
28 | title: '用户',
29 | },
30 | ];
31 |
--------------------------------------------------------------------------------
/src/pages/search/menus.js:
--------------------------------------------------------------------------------
1 | export default [
2 | {
3 | key: 'all',
4 | title: '全部',
5 | },
6 | {
7 | key: 'question',
8 | title: '问题',
9 | },
10 | {
11 | key: 'answer',
12 | title: '回答',
13 | },
14 | {
15 | key: 'article',
16 | title: '文章',
17 | },
18 | {
19 | key: 'column',
20 | title: '专栏',
21 | },
22 | {
23 | key: 'tag',
24 | title: '标签',
25 | },
26 | {
27 | key: 'user',
28 | title: '用户',
29 | },
30 | ];
31 |
--------------------------------------------------------------------------------
/src/components/Button/EditButton.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import BaseButton from './BaseButton';
3 | import { EditOutlined } from '@ant-design/icons';
4 |
5 | function EditButton({ children, onlyIcon, text, ...props }) {
6 | text = text || '编辑';
7 | const renderContent = () => {
8 | if (children) return children;
9 | return text;
10 | };
11 |
12 | return (
13 | } {...props}>
14 | {!onlyIcon && renderContent()}
15 |
16 | );
17 | }
18 | export default EditButton;
19 |
--------------------------------------------------------------------------------
/src/components/Button/DeleteButton.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import BaseButton from './BaseButton';
3 | import { DeleteOutlined } from '@ant-design/icons';
4 |
5 | function DeleteButton({ text, onlyIcon, children, ...props }) {
6 | text = text || '删除';
7 | const renderContent = () => {
8 | if (children) return children;
9 | return text;
10 | };
11 | return (
12 | } {...props}>
13 | {!onlyIcon && renderContent()}
14 |
15 | );
16 | }
17 | export default DeleteButton;
18 |
--------------------------------------------------------------------------------
/src/services/tag/star.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function list(params) {
4 | return request(`/api/tag/star`, {
5 | params,
6 | });
7 | }
8 |
9 | export async function follow({ id }) {
10 | return request(`/api/tag/star`, {
11 | method: 'POST',
12 | data: {
13 | id,
14 | },
15 | });
16 | }
17 |
18 | export async function unfollow({ id }) {
19 | return request(`/api/tag/star`, {
20 | method: 'DELETE',
21 | data: {
22 | id,
23 | },
24 | });
25 | }
26 |
--------------------------------------------------------------------------------
/src/pages/user/dashboard/income/components/Total/index.less:
--------------------------------------------------------------------------------
1 | .ratio {
2 | font-size: 12px;
3 | margin-left: 5px;
4 |
5 | .label {
6 | color: rgba(0, 0, 0, 0.45);
7 | }
8 |
9 | :global {
10 | .ant-statistic {
11 | font-size: 12px;
12 |
13 | .ant-statistic-content {
14 | font-size: 14px;
15 |
16 | .ant-statistic-content-value-decimal,
17 | .ant-statistic-content-suffix {
18 | font-size: 14px;
19 | }
20 | }
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/pages/user/notifications/components/Layout/index.js:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react';
2 | import { Layout, Sider } from '@/components/Container';
3 | import { RouteContext } from '@/context';
4 | import siderData from './sider';
5 |
6 | export default ({ children, defaultKey }) => {
7 | const { isMobile } = useContext(RouteContext);
8 |
9 | return (
10 |
11 | {!isMobile && }
12 | {children}
13 |
14 | );
15 | };
16 |
--------------------------------------------------------------------------------
/src/services/answer/star.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 | export async function list(params) {
3 | return request(`/api/answer/star`, {
4 | params,
5 | });
6 | }
7 |
8 | export async function follow({ id }) {
9 | return request(`/api/answer/star`, {
10 | method: 'POST',
11 | data: {
12 | id,
13 | },
14 | });
15 | }
16 |
17 | export async function unfollow({ id }) {
18 | return request(`/api/answer/star`, {
19 | method: 'DELETE',
20 | data: {
21 | id,
22 | },
23 | });
24 | }
25 |
--------------------------------------------------------------------------------
/src/components/Editor/Plugin/PaidContent.js:
--------------------------------------------------------------------------------
1 | const PLUGIN_NAME = 'paid-content';
2 | export default {
3 | initialize: function () {
4 | // 创建命令
5 | this.command.add(PLUGIN_NAME, {
6 | execute: () => {
7 | this.change.insertSection(PLUGIN_NAME);
8 | },
9 | });
10 | // 快捷键
11 | const options = this.options[PLUGIN_NAME] || {
12 | hotkey: 'mod+shift+m',
13 | };
14 |
15 | if (!!options.hotkey) {
16 | this.hotkey.set(options.hotkey, PLUGIN_NAME);
17 | }
18 | },
19 | };
20 |
--------------------------------------------------------------------------------
/src/pages/user/dashboard/analytics/components/Total/index.less:
--------------------------------------------------------------------------------
1 | .ratio {
2 | font-size: 12px;
3 | margin-left: 5px;
4 |
5 | .label {
6 | color: rgba(0, 0, 0, 0.45);
7 | }
8 |
9 | :global {
10 | .ant-statistic {
11 | font-size: 12px;
12 |
13 | .ant-statistic-content {
14 | font-size: 14px;
15 |
16 | .ant-statistic-content-value-decimal,
17 | .ant-statistic-content-suffix {
18 | font-size: 14px;
19 | }
20 | }
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/services/column/star.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function list(params) {
4 | return request(`/api/column/star`, {
5 | params,
6 | });
7 | }
8 |
9 | export async function follow({ id }) {
10 | return request(`/api/column/star`, {
11 | method: 'POST',
12 | data: {
13 | id,
14 | },
15 | });
16 | }
17 |
18 | export async function unfollow({ id }) {
19 | return request(`/api/column/star`, {
20 | method: 'DELETE',
21 | data: {
22 | id,
23 | },
24 | });
25 | }
26 |
--------------------------------------------------------------------------------
/src/components/Button/ReportButton/Modal.less:
--------------------------------------------------------------------------------
1 | .container {
2 | .title {
3 | font-size: 16px;
4 | font-weight: 700;
5 | }
6 |
7 | .sub-title{
8 | color: #8c8c8c;
9 | margin: 10px 0;
10 | }
11 |
12 | .content {
13 | font-weight: 700;
14 |
15 | ul,li{
16 | padding: 0;
17 | margin: 0;
18 | }
19 |
20 | .content-item {
21 | display: block;
22 | cursor: pointer;
23 | border-bottom: 1px solid #e8e8e8;
24 | padding: 12px 0;
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/src/services/article/star.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function list(params) {
4 | return request(`/api/article/star`, {
5 | params,
6 | });
7 | }
8 |
9 | export async function follow({ id }) {
10 | return request(`/api/article/star`, {
11 | method: 'POST',
12 | data: {
13 | id,
14 | },
15 | });
16 | }
17 |
18 | export async function unfollow({ id }) {
19 | return request(`/api/article/star`, {
20 | method: 'DELETE',
21 | data: {
22 | id,
23 | },
24 | });
25 | }
26 |
--------------------------------------------------------------------------------
/src/pages/user/dashboard/analytics/service.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function searchByDate({ type, ...params }) {
4 | return request(`/api/statistics/search/${type}/group`, {
5 | params,
6 | });
7 | }
8 |
9 | export async function searchByContent({ type, ...params }) {
10 | return request(`/api/statistics/search/content/${type}`, {
11 | params,
12 | });
13 | }
14 |
15 | export async function searchByTotal({ type, ...params }) {
16 | return request(`/api/statistics/search/${type}/total`, {
17 | params,
18 | });
19 | }
20 |
--------------------------------------------------------------------------------
/src/services/question/star.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function list(params) {
4 | return request(`/api/question/star`, {
5 | params,
6 | });
7 | }
8 |
9 | export async function follow({ id }) {
10 | return request(`/api/question/star`, {
11 | method: 'POST',
12 | data: {
13 | id,
14 | },
15 | });
16 | }
17 |
18 | export async function unfollow({ id }) {
19 | return request(`/api/question/star`, {
20 | method: 'DELETE',
21 | data: {
22 | id,
23 | },
24 | });
25 | }
26 |
--------------------------------------------------------------------------------
/src/pages/user/dashboard/income/components/Content/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Card } from 'antd';
3 | import List from './List';
4 | import styles from './index.less';
5 |
6 | const Content = () => {
7 | return (
8 |
9 |
10 |
11 | );
12 | };
13 | Content.getInitialProps = async ({ isServer, store, params }) => {
14 | const { getState } = store;
15 | await List.getInitialProps({ isServer, store, params });
16 | if (isServer) return getState();
17 | };
18 |
19 | export default Content;
20 |
--------------------------------------------------------------------------------
/src/components/Button/CommentButton.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import BaseButton from './BaseButton';
3 | import { MessageOutlined } from '@ant-design/icons';
4 |
5 | const CommentButton = React.forwardRef(({ count, children, ...props }, ref) => {
6 | const getContent = () => {
7 | if (children) return children;
8 | return count === 0 || !count ? '添加评论' : `${count}条评论`;
9 | };
10 |
11 | return (
12 | } {...props} ref={ref}>
13 | {getContent()}
14 |
15 | );
16 | });
17 | export default CommentButton;
18 |
--------------------------------------------------------------------------------
/src/locales/zh-CN.js:
--------------------------------------------------------------------------------
1 | export default {
2 | keywords:
3 | 'itellyou,itellyou官网,我告诉你,MSDN我告诉你,itellyou我告诉你,windows原版系统iso文件下载',
4 | description:
5 | 'itellyou,我告诉你,提供windows11、windows10、windows7、windows8、Linux、macOs、Chromiumos、等微软原版系统iso文件下载',
6 | 'sys.path': '无标题',
7 | 'preview.page': '预览',
8 | '403.page': '403 - No Access',
9 | 403: 'Sorry, you are not authorized to access this page.',
10 | '404.page': '404 - Not Found',
11 | 404: 'Sorry, the page you visited does not exist.',
12 | '500.page': '500 - Error',
13 | 500: 'An error occurred in the service',
14 | };
15 |
--------------------------------------------------------------------------------
/src/components/List/Default.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { List, Empty } from 'antd';
3 |
4 | const Default = ({ loading, dataSource, renderHeader, ...props }) => {
5 | renderHeader = renderHeader || function() {};
6 |
7 | const renderList = () => {
8 | return (
9 |
10 | );
11 | };
12 |
13 | if (dataSource && dataSource.length === 0) return ;
14 |
15 | return renderList();
16 | };
17 |
18 | Default.Item = List.Item;
19 | export default Default;
20 |
--------------------------------------------------------------------------------
/src/components/Loading/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Spin } from 'antd';
3 | import LoadingButton from './Button';
4 | import styles from './index.less';
5 | import { LoadingOutlined } from '@ant-design/icons';
6 |
7 | export default ({ tip, loading, children }) => (
8 | }
11 | tip={tip || '加载中...'}
12 | spinning={loading === undefined || loading === null ? true : loading}
13 | >
14 | {children}
15 |
16 | );
17 |
18 | export { LoadingButton };
19 |
--------------------------------------------------------------------------------
/src/components/Tag/Create/formMap.js:
--------------------------------------------------------------------------------
1 | export default {
2 | TagName: {
3 | props: {
4 | placeholder: '标签名称',
5 | },
6 | rules: [
7 | {
8 | required: true,
9 | message: '标签名称不可以为空',
10 | },
11 | {
12 | min: 1,
13 | max: 32,
14 | message: '长度为1-32个字符',
15 | },
16 | /**{
17 | pattern: /^[\u4e00-\u9fa5_A-Za-z0-9-\.#&@+]*$/,
18 | message: '名称只支持中英文、数字、_、-、.、#、&、@、+',
19 | },**/
20 | ],
21 | },
22 | };
23 |
--------------------------------------------------------------------------------
/src/pages/user/login/service.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function loginByAccount(params) {
4 | return request('/api/user/login/account', {
5 | method: 'POST',
6 | data: params,
7 | });
8 | }
9 |
10 | export async function loginByMobile(params) {
11 | return request('/api/user/login/mobile', {
12 | method: 'POST',
13 | data: params,
14 | });
15 | }
16 |
17 | export async function loginByOauth({ type, ...params }) {
18 | return request(`/api/oauth/${type}/login`, {
19 | method: 'POST',
20 | data: params,
21 | });
22 | }
23 |
--------------------------------------------------------------------------------
/src/components/Header/Container.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import classNames from 'classnames';
3 | import Container from '@/components/Container';
4 | import styles from './index.less';
5 |
6 | export default ({ className, mode, isMobile, children, before, after }) => {
7 | return (
8 |
9 |
10 | {before}
11 | {children}
12 | {after && {after}
}
13 |
14 |
15 | );
16 | };
17 |
--------------------------------------------------------------------------------
/src/wrappers/auth.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { useAccess, Redirect } from 'umi';
3 | import { getRoute } from '@/utils/page';
4 |
5 | export default ({ children, route, location: { pathname } }) => {
6 | const { routes = [] } = route || {};
7 |
8 | if (route && !route.routes) {
9 | routes.push(route);
10 | }
11 | const routeData = getRoute(pathname, routes);
12 | if (routeData && routeData.unaccessible) {
13 | const access = useAccess();
14 | if (!access.isLogin) return ;
15 | return ;
16 | }
17 | return children;
18 | };
19 |
--------------------------------------------------------------------------------
/src/pages/article/components/HistoryExtra/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Tag from '@/components/Tag';
3 | import styles from './index.less';
4 |
5 | export default ({ title, tags }) => {
6 | let rewardMessage = '';
7 | return (
8 |
9 |
{title}
10 |
11 | {tags.map(({ id, name }) => (
12 |
13 | ))}
14 |
15 |
{rewardMessage}
16 |
17 | );
18 | };
19 |
--------------------------------------------------------------------------------
/src/pages/path/components/user/components/Activity.less:
--------------------------------------------------------------------------------
1 | .verb {
2 | margin-bottom: 16px;
3 | }
4 |
5 | h2 {
6 | font-size: 18px;
7 | margin-bottom: 0;
8 |
9 | a,
10 | a:hover,
11 | a:focus {
12 | color: #262626;
13 | }
14 | }
15 |
16 | .column {
17 | display: flex;
18 |
19 | .avatar {
20 | margin-right: 16px;
21 | margin-top: 10px;
22 | }
23 |
24 | .content {
25 | p {
26 | margin-bottom: 0;
27 | }
28 | }
29 | }
30 |
31 | .tag {
32 | p {
33 | margin-bottom: 0;
34 | }
35 | }
36 |
37 | .question-title {
38 | margin-bottom: 16px;
39 | }
40 |
--------------------------------------------------------------------------------
/src/pages/user/notifications/components/Layout/sider.js:
--------------------------------------------------------------------------------
1 | export default [
2 | {
3 | key: 'default',
4 | title: '全部消息',
5 | to: '/notifications',
6 | },
7 | {
8 | key: 'follow',
9 | title: '关注我的',
10 | to: '/notifications/follow',
11 | },
12 | {
13 | key: 'like',
14 | title: '赞我的',
15 | to: '/notifications/like',
16 | },
17 | {
18 | key: 'comment',
19 | title: '评论与回复',
20 | to: '/notifications/comment',
21 | },
22 | {
23 | key: 'publish',
24 | title: '关注的动态',
25 | to: '/notifications/publish',
26 | },
27 | ];
28 |
--------------------------------------------------------------------------------
/src/pages/user/settings/components/Layout/index.js:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react';
2 | import Container, { Layout, Sider } from '@/components/Container';
3 | import { RouteContext } from '@/context';
4 | import siderData from './sider';
5 |
6 | export default ({ children, defaultKey }) => {
7 | const { isMobile } = useContext(RouteContext);
8 |
9 | return (
10 |
11 |
12 | {!isMobile && }
13 | {children}
14 |
15 |
16 | );
17 | };
18 |
--------------------------------------------------------------------------------
/src/pages/Tag/detail/components/Column.less:
--------------------------------------------------------------------------------
1 | .column {
2 | display: flex;
3 |
4 | .avatar {
5 | margin-right: 16px;
6 | }
7 |
8 | .info {
9 | .title {
10 | margin: 0;
11 | font-size: 18px;
12 | font-weight: 600;
13 | line-height: 1.6;
14 | }
15 |
16 | .desc {
17 | color: #646464;
18 | overflow: hidden;
19 | text-overflow: ellipsis;
20 | white-space: nowrap;
21 | font-size: 15px;
22 | }
23 |
24 | .status {
25 | color: #8590a6;
26 | font-size: 14px;
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/pages/Tag/detail/menu.js:
--------------------------------------------------------------------------------
1 | import Intro from './components/Intro';
2 | import Question from './components/Question';
3 | import Article from './components/Article';
4 | import Column from './components/Column';
5 |
6 | export default [
7 | {
8 | key: 'intro',
9 | title: '简介',
10 | component: Intro,
11 | },
12 | {
13 | key: 'question',
14 | title: '问题',
15 | component: Question,
16 | },
17 | {
18 | key: 'article',
19 | title: '文章',
20 | component: Article,
21 | },
22 | {
23 | key: 'column',
24 | title: '专栏',
25 | component: Column,
26 | },
27 | ];
28 |
--------------------------------------------------------------------------------
/src/pages/tag/detail/components/Column.less:
--------------------------------------------------------------------------------
1 | .column {
2 | display: flex;
3 |
4 | .avatar {
5 | margin-right: 16px;
6 | }
7 |
8 | .info {
9 | .title {
10 | margin: 0;
11 | font-size: 18px;
12 | font-weight: 600;
13 | line-height: 1.6;
14 | }
15 |
16 | .desc {
17 | color: #646464;
18 | overflow: hidden;
19 | text-overflow: ellipsis;
20 | white-space: nowrap;
21 | font-size: 15px;
22 | }
23 |
24 | .status {
25 | color: #8590a6;
26 | font-size: 14px;
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/pages/tag/detail/menu.js:
--------------------------------------------------------------------------------
1 | import Intro from './components/Intro';
2 | import Question from './components/Question';
3 | import Article from './components/Article';
4 | import Column from './components/Column';
5 |
6 | export default [
7 | {
8 | key: 'intro',
9 | title: '简介',
10 | component: Intro,
11 | },
12 | {
13 | key: 'question',
14 | title: '问题',
15 | component: Question,
16 | },
17 | {
18 | key: 'article',
19 | title: '文章',
20 | component: Article,
21 | },
22 | {
23 | key: 'column',
24 | title: '专栏',
25 | component: Column,
26 | },
27 | ];
28 |
--------------------------------------------------------------------------------
/src/pages/user/dashboard/components/Layout/index.js:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react';
2 | import Container, { Layout } from '@/components/Container';
3 | import { RouteContext } from '@/context';
4 | import Nav from './Nav';
5 | import siderData from './sider';
6 |
7 | export default ({ children, defaultKey }) => {
8 | const { isMobile } = useContext(RouteContext);
9 | return (
10 |
11 |
12 | {!isMobile && }
13 | {children}
14 |
15 |
16 | );
17 | };
18 |
--------------------------------------------------------------------------------
/src/services/reward.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function findConfig(params) {
4 | return request('/api/reward/config', {
5 | method: 'GET',
6 | data: params,
7 | });
8 | }
9 |
10 | export async function doReward(params) {
11 | return request('/api/reward/do', {
12 | method: 'POST',
13 | data: params,
14 | });
15 | }
16 |
17 | export async function list(params) {
18 | return request('/api/reward/list', {
19 | params,
20 | });
21 | }
22 |
23 | export async function answerList(params) {
24 | return request('/api/reward/answer/list', {
25 | params,
26 | });
27 | }
28 |
--------------------------------------------------------------------------------
/src/pages/software/edit/components/Setting/formMap.js:
--------------------------------------------------------------------------------
1 | import { Input } from 'antd';
2 |
3 | export default {
4 | Logo: {
5 | props: {
6 | type: 'hidden',
7 | },
8 | },
9 | Name: {
10 | props: {
11 | size: 'large',
12 | placeholder: '名称',
13 | },
14 | rules: [
15 | {
16 | required: true,
17 | message: '请输入名称',
18 | },
19 | ],
20 | },
21 | Desc: {
22 | component: Input.TextArea,
23 | props: {
24 | autoSize: { minRows: 3, maxRows: 6 },
25 | maxLength: 200,
26 | },
27 | },
28 | };
29 |
--------------------------------------------------------------------------------
/src/services/notifications.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function count(params) {
4 | return request('/api/notifications/count', {
5 | params,
6 | });
7 | }
8 |
9 | export async function list(params) {
10 | return request('/api/notifications', {
11 | params,
12 | });
13 | }
14 |
15 | export async function readed(params) {
16 | return request(`/api/notifications`, {
17 | method: 'PUT',
18 | data: params,
19 | });
20 | }
21 |
22 | export async function deleted(params) {
23 | return request(`/api/notifications`, {
24 | method: 'DELETE',
25 | data: params,
26 | });
27 | }
28 |
--------------------------------------------------------------------------------
/src/components/Button/BackTopButton.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { BackTop, Tooltip } from 'antd';
3 | import { VerticalAlignTopOutlined } from '@ant-design/icons';
4 | import BaseButton from './BaseButton';
5 |
6 | export default React.forwardRef((_, ref) => {
7 | return (
8 |
9 |
10 | }
13 | shape="circle"
14 | />
15 |
16 |
17 | );
18 | });
19 |
--------------------------------------------------------------------------------
/src/pages/document.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | <% if (context.title != null) { %>
10 | <%= context.title %>
11 | <% } %>
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/pages/user/dashboard/components/CardMenu/index.less:
--------------------------------------------------------------------------------
1 | .card-menu-wrapper {
2 | > .ant-card > .ant-card-head > .ant-card-head-wrapper .ant-card-head-title {
3 | padding: 0;
4 |
5 | .ant-menu {
6 | font-size: 16px;
7 | }
8 | }
9 |
10 | > .ant-card > .ant-card-head {
11 | margin-bottom: 0;
12 | padding: 0;
13 | }
14 | }
15 |
16 | .card-full-wrapper {
17 | > .ant-card > .ant-card-body {
18 | padding: 0;
19 | }
20 | }
21 |
22 | .card-no-header {
23 | > .ant-card > .ant-card-body {
24 | padding: 0;
25 | }
26 |
27 | .ant-table-thead > tr > th {
28 | background: transparent;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/pages/user/dashboard/wallet/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Layout from '../components/Layout';
3 | import Access from './components/Access';
4 | import Log from './components/Log';
5 |
6 | const Wallet = () => {
7 | return (
8 |
9 |
10 |
11 |
12 | );
13 | };
14 |
15 | Wallet.getInitialProps = async ({ isServer, store, params }) => {
16 | const { getState } = store;
17 | await Access.getInitialProps({ isServer, store, params });
18 | await Log.getInitialProps({ isServer, store, params });
19 | if (isServer) return getState();
20 | };
21 |
22 | export default Wallet;
23 |
--------------------------------------------------------------------------------
/src/pages/user/dashboard/components/Layout/Nav/index.less:
--------------------------------------------------------------------------------
1 | .nav {
2 | .divider {
3 | display: block;
4 | height: 1px;
5 | background: #e8e8e8;
6 | margin-top: 10px;
7 | margin-left: 0;
8 | margin-bottom: 10px;
9 | width: 25px;
10 | }
11 |
12 | a {
13 | display: block;
14 | line-height: 40px;
15 | padding-left: 0;
16 | color: #8c8c8c;
17 |
18 | :global(.anticon) {
19 | margin-right: 10px;
20 | }
21 | }
22 |
23 | a:hover {
24 | background: #f5f5f5;
25 | box-shadow: -10px 0 #f5f5f5;
26 | }
27 |
28 | a.active {
29 | color: @primary-color;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/services/user/star.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function star(params) {
4 | return request(`/api/user/star`, {
5 | params,
6 | });
7 | }
8 |
9 | export async function follower(params) {
10 | return request(`/api/user/follower`, {
11 | params,
12 | });
13 | }
14 |
15 | export async function follow({ id }) {
16 | return request(`/api/user/star`, {
17 | method: 'POST',
18 | data: {
19 | id,
20 | },
21 | });
22 | }
23 |
24 | export async function unfollow({ id }) {
25 | return request(`/api/user/star`, {
26 | method: 'DELETE',
27 | data: {
28 | id,
29 | },
30 | });
31 | }
32 |
--------------------------------------------------------------------------------
/src/models/article/reward.js:
--------------------------------------------------------------------------------
1 | import { list } from '@/services/reward';
2 | import { setList } from '@/utils/model';
3 |
4 | export default {
5 | namespace: 'articleReward',
6 |
7 | state: {},
8 | effects: {
9 | *list({ payload: { append, id, ...payload } }, { call, put }) {
10 | const response = yield call(list, { ...payload, data_type: 'article', data_key: id });
11 | yield put({
12 | type: 'setList',
13 | payload: { append, ...(response.data || {}) },
14 | });
15 | },
16 | },
17 | reducers: {
18 | setList(state, { payload }) {
19 | return setList('list', payload, state);
20 | },
21 | },
22 | };
23 |
--------------------------------------------------------------------------------
/src/models/software/group.js:
--------------------------------------------------------------------------------
1 | import { list } from '@/services/software/group';
2 | import { setList } from '@/utils/model';
3 |
4 | export default {
5 | namespace: 'softwareGroup',
6 |
7 | state: {},
8 |
9 | effects: {
10 | *list({ payload: { append, ...payload } }, { call, put }) {
11 | const response = yield call(list, payload);
12 | yield put({
13 | type: 'setList',
14 | payload: { append, ...(response.data || {}) },
15 | });
16 | return response;
17 | },
18 | },
19 | reducers: {
20 | setList(state, { payload }) {
21 | return setList('list', payload, state);
22 | },
23 | },
24 | };
25 |
--------------------------------------------------------------------------------
/src/models/software/reward.js:
--------------------------------------------------------------------------------
1 | import { list } from '@/services/reward';
2 | import { setList } from '@/utils/model';
3 |
4 | export default {
5 | namespace: 'softwareReward',
6 |
7 | state: {},
8 | effects: {
9 | *list({ payload: { append, id, ...payload } }, { call, put }) {
10 | const response = yield call(list, { ...payload, data_type: 'software', data_key: id });
11 | yield put({
12 | type: 'setList',
13 | payload: { append, ...(response.data || {}) },
14 | });
15 | },
16 | },
17 | reducers: {
18 | setList(state, { payload }) {
19 | return setList('list', payload, state);
20 | },
21 | },
22 | };
23 |
--------------------------------------------------------------------------------
/src/pages/user/dashboard/history/model.js:
--------------------------------------------------------------------------------
1 | import { list } from './service';
2 | import { setList } from '@/utils/model';
3 | export default {
4 | namespace: 'history',
5 |
6 | state: {},
7 |
8 | effects: {
9 | *list({ payload: { append, ...payload } }, { call, put }) {
10 | const response = yield call(list, payload);
11 | yield put({
12 | type: 'setList',
13 | payload: { append, ...(response ? response.data : {}) },
14 | });
15 | return response;
16 | },
17 | },
18 |
19 | reducers: {
20 | setList(state, { payload }) {
21 | return setList('list', payload, state);
22 | },
23 | },
24 | };
25 |
--------------------------------------------------------------------------------
/src/pages/preview/model.js:
--------------------------------------------------------------------------------
1 | import { getURL } from './service';
2 | export default {
3 | namespace: 'preview',
4 |
5 | state: {
6 | urls: {},
7 | },
8 |
9 | effects: {
10 | *getURL({ payload }, { call, put }) {
11 | const response = yield call(getURL, payload);
12 | yield put({
13 | type: 'setURL',
14 | payload: { key: payload.key, data: response.data },
15 | });
16 | return response;
17 | },
18 | },
19 |
20 | reducers: {
21 | setURL(state, { payload: { key, data } }) {
22 | return {
23 | ...state,
24 | [key]: data,
25 | };
26 | },
27 | },
28 | };
29 |
--------------------------------------------------------------------------------
/src/components/Button/SupportButton.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { LikeFilled } from '@ant-design/icons';
3 | import BaseButton from './BaseButton';
4 |
5 | const SupportButton = React.forwardRef(({ text, count, icon, children, ...props }, ref) => {
6 | count = count || 0;
7 | const renderContent = () => {
8 | if (children) return children;
9 | return (
10 |
11 | {!text && count > 0 && count}
12 | {text || '赞'}
13 |
14 | );
15 | };
16 |
17 | return (
18 | } ref={ref} {...props}>
19 | {renderContent()}
20 |
21 | );
22 | });
23 | export default SupportButton;
24 |
--------------------------------------------------------------------------------
/src/components/Button/BaseButton.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Button } from 'antd';
3 | import classnames from 'classnames';
4 | import styles from './index.less';
5 |
6 | const BaseButton = React.forwardRef(({ children, active, loading, icon, ...props }, ref) => {
7 | const getIcon = () => {
8 | if (loading) return;
9 | return icon;
10 | };
11 | return (
12 |
22 | );
23 | });
24 | export default BaseButton;
25 |
--------------------------------------------------------------------------------
/src/components/Timer/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Tooltip } from 'antd';
3 | import timeUtils from '@/utils/time';
4 | export default ({ placement, className, useTip, time }) => {
5 | placement = placement || 'bottom';
6 |
7 | const formattedTime = timeUtils.format(time);
8 |
9 | const getFormattedTime = () => {
10 | return {formattedTime};
11 | };
12 |
13 | if (!useTip) {
14 | return getFormattedTime();
15 | }
16 |
17 | return (
18 |
24 | {getFormattedTime()}
25 |
26 | );
27 | };
28 |
--------------------------------------------------------------------------------
/src/services/software/index.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function list(params) {
4 | return request(`/api/software/list`, {
5 | params,
6 | });
7 | }
8 |
9 | export async function find({ id, ...params }) {
10 | return request(`/api/software/${id}`, {
11 | params,
12 | });
13 | }
14 |
15 | export async function view({ id, ...params }) {
16 | return request(`/api/software/${id}/view`, {
17 | params,
18 | });
19 | }
20 |
21 | export async function vote({ id, type }) {
22 | return request(`/api/software/${id}/${type}`, {
23 | method: 'POST',
24 | });
25 | }
26 |
27 | export async function del({ id }) {
28 | return request(`/api/software/${id}`, {
29 | method: 'DELETE',
30 | });
31 | }
32 |
--------------------------------------------------------------------------------
/src/components/Editor/Collab/ot/logger/logger.js:
--------------------------------------------------------------------------------
1 | var SUPPORTED_METHODS = ['info', 'warn', 'error'];
2 |
3 | function Logger() {
4 | var defaultMethods = {};
5 | SUPPORTED_METHODS.forEach(function(method) {
6 | // Deal with Chrome issue: https://bugs.chromium.org/p/chromium/issues/detail?id=179628
7 | defaultMethods[method] = console[method].bind(console);
8 | });
9 | this.setMethods(defaultMethods);
10 | }
11 | module.exports = Logger;
12 |
13 | Logger.prototype.setMethods = function(overrides) {
14 | overrides = overrides || {};
15 | var logger = this;
16 |
17 | SUPPORTED_METHODS.forEach(function(method) {
18 | if (typeof overrides[method] === 'function') {
19 | logger[method] = overrides[method];
20 | }
21 | });
22 | };
23 |
--------------------------------------------------------------------------------
/src/components/Editor/Collab/ot/util.js:
--------------------------------------------------------------------------------
1 | exports.doNothing = doNothing;
2 | function doNothing() {}
3 |
4 | exports.hasKeys = function(object) {
5 | for (var key in object) return true;
6 | return false;
7 | };
8 |
9 | // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger#Polyfill
10 | exports.isInteger =
11 | Number.isInteger ||
12 | function(value) {
13 | return typeof value === 'number' && isFinite(value) && Math.floor(value) === value;
14 | };
15 |
16 | exports.isValidVersion = function(version) {
17 | if (version === null) return true;
18 | return exports.isInteger(version) && version >= 0;
19 | };
20 |
21 | exports.isValidTimestamp = function(timestamp) {
22 | return exports.isValidVersion(timestamp);
23 | };
24 |
--------------------------------------------------------------------------------
/src/models/answer/group-user.js:
--------------------------------------------------------------------------------
1 | import { list } from '@/services/answer/group-user';
2 | export default {
3 | namespace: 'answerGroupUser',
4 |
5 | state: {},
6 | effects: {
7 | *list({ payload }, { call, put }) {
8 | const response = yield call(list, payload);
9 | const { result, data } = response || {};
10 | if (result) {
11 | yield put({
12 | type: 'setList',
13 | payload: data,
14 | });
15 | }
16 | return response;
17 | },
18 | },
19 | reducers: {
20 | setList(state, { payload }) {
21 | return {
22 | ...state,
23 | list: payload,
24 | };
25 | },
26 | },
27 | };
28 |
--------------------------------------------------------------------------------
/src/models/answer/reward.js:
--------------------------------------------------------------------------------
1 | import { answerList } from '@/services/reward';
2 | import { setList } from '@/utils/model';
3 |
4 | export default {
5 | namespace: 'answerReward',
6 |
7 | state: {},
8 | effects: {
9 | *list({ payload: { append, ...payload } }, { call, put }) {
10 | const response = yield call(answerList, { ...payload, data_type: 'answer' });
11 | if (response && response.result) {
12 | yield put({
13 | type: 'setList',
14 | payload: { append, ...(response.data || {}) },
15 | });
16 | }
17 | },
18 | },
19 | reducers: {
20 | setList(state, { payload }) {
21 | return setList('list', payload, state);
22 | },
23 | },
24 | };
25 |
--------------------------------------------------------------------------------
/src/pages/article/detail/Related.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { useSelector } from 'umi';
3 | import List from '@/components/List';
4 | import Loading from '@/components/Loading';
5 | import { Article } from '@/components/Content';
6 | import { Card } from 'antd';
7 |
8 | export default () => {
9 | const renderItem = item => {
10 | return (
11 |
12 |
13 |
14 | );
15 | };
16 |
17 | const dataSource = useSelector(state => state.article.related);
18 | if (!dataSource) return ;
19 |
20 | return (
21 |
22 |
23 |
24 | );
25 | };
26 |
--------------------------------------------------------------------------------
/src/pages/question/detail/components/Author/index.less:
--------------------------------------------------------------------------------
1 | .author {
2 | .data {
3 | justify-content: space-between;
4 | margin: 16px 0 0 0;
5 | padding: 16px 0 0 0;
6 | border-top: 1px dashed #f0f0f0;
7 |
8 | .follow {
9 | text-align: center;
10 | display: flex;
11 |
12 | .item {
13 | color: #bfbfbf;
14 | width: 25%;
15 |
16 | .count {
17 | color: #262626;
18 | }
19 | }
20 | }
21 |
22 | .user-link {
23 | float: right;
24 | }
25 | }
26 |
27 | .btn {
28 | text-align: center;
29 | margin-top: 24px;
30 |
31 | .star {
32 | width: 50%;
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/components/Header/Burger/index.less:
--------------------------------------------------------------------------------
1 | .nav-burger {
2 | width: 120px;
3 |
4 | .btn-burger {
5 | font-size: 16px;
6 | }
7 | }
8 |
9 | .nav-burger-body {
10 | padding: 16px;
11 | }
12 |
13 | .burger-mask {
14 | position: absolute;
15 | z-index: 998;
16 | top: 0;
17 | width: 100%;
18 | height: 100vh;
19 | background-color: rgba(0, 0, 0, 0.4);
20 | }
21 |
22 | .burger-menu {
23 | position: fixed;
24 | z-index: 998;
25 | top: -10px;
26 | left: 0;
27 | right: 0;
28 | opacity: 0;
29 | background-color: #fff;
30 | transition: top 0.2s cubic-bezier(0.645, 0.045, 0.355, 1) 0.05s,
31 | opacity 0.15s cubic-bezier(0.645, 0.045, 0.355, 1) 0.05s;
32 | max-height: calc(100vh - 200px);
33 | overflow-y: auto;
34 | overflow-x: hidden;
35 | }
36 |
--------------------------------------------------------------------------------
/src/components/Pay/QrCode/index.less:
--------------------------------------------------------------------------------
1 | .warpper {
2 | .title {
3 | font-size: 16px;
4 | text-align: center;
5 |
6 | .desc {
7 | margin: 0;
8 | }
9 |
10 | .amount {
11 | color: #e96a30;
12 | font-size: 28px;
13 | margin: 5px 10px;
14 | font-weight: 600;
15 | }
16 | }
17 |
18 | .qr-code {
19 | position: relative;
20 | width: 260px;
21 | height: 260px;
22 | margin: 0 auto;
23 | border: 1px solid #efefef;
24 | border-radius: 1px;
25 | overflow: hidden;
26 | }
27 |
28 | .footer {
29 | color: #595959;
30 | font-size: 14px;
31 | margin-top: 24px;
32 | text-align: center;
33 | padding-bottom: 40px;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/components/Tag/Brand/index.less:
--------------------------------------------------------------------------------
1 | .tag-card {
2 | width: 346px;
3 | padding: 4px 0;
4 |
5 | .body {
6 | display: flex;
7 |
8 | .info {
9 | margin-left: 16px;
10 | word-wrap: break-word;
11 | word-break: break-all;
12 | }
13 | }
14 |
15 | .footer {
16 | margin-top: 16px;
17 | padding: 12px 16px 0;
18 | border-top: 1px solid #f5f5f5;
19 | text-align: center;
20 |
21 | .follow {
22 | display: flex;
23 | margin-bottom: 16px;
24 |
25 | .item {
26 | flex: 1;
27 | color: #bfbfbf;
28 | .count {
29 | display: block;
30 | color: #262626;
31 | }
32 | }
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/pages/question/components/HistoryExtra/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Tag from '@/components/Tag';
3 | import styles from './index.less';
4 |
5 | export default ({ title, tags, reward_type, reward_value }) => {
6 | let rewardMessage = '无悬赏';
7 | if (reward_type === 'credit') rewardMessage = `悬赏 ${reward_value} 积分`;
8 | else if (reward_type === 'cash') rewardMessage = `悬赏 ${reward_value} 元`;
9 |
10 | return (
11 |
12 |
{title}
13 |
14 | {tags.map(({ id, name }) => (
15 |
16 | ))}
17 |
18 |
{rewardMessage}
19 |
20 | );
21 | };
22 |
--------------------------------------------------------------------------------
/src/services/column/index.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function create(params) {
4 | return request('/api/column/create', {
5 | method: 'PUT',
6 | data: params,
7 | });
8 | }
9 |
10 | export async function list(params) {
11 | return request(`/api/column/list`, {
12 | params,
13 | });
14 | }
15 |
16 | export async function detail(params) {
17 | return request(`/api/column/detail`, {
18 | params,
19 | });
20 | }
21 |
22 | export async function queryName(params) {
23 | return request('/api/column/query/name', {
24 | method: 'POST',
25 | data: params,
26 | });
27 | }
28 |
29 | export async function setting(params) {
30 | return request('/api/column/setting', {
31 | method: 'PUT',
32 | data: params,
33 | });
34 | }
35 |
--------------------------------------------------------------------------------
/src/components/Ad/Baidu.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useRef } from 'react';
2 |
3 | export default ({ style, slot_id }) => {
4 | const div = useRef();
5 |
6 | useEffect(() => {
7 | let id = div.current.getAttribute('id');
8 | if (!id) {
9 | id = '_' + Math.random().toString(36).slice(2);
10 | div.current.setAttribute('id', id);
11 | div.current.setAttribute('style', style);
12 | }
13 | try {
14 | if (typeof window === 'undefined') return;
15 | (window.slotbydup = window.slotbydup || []).push({
16 | id: slot_id,
17 | container: id,
18 | async: true,
19 | });
20 | } catch (e) {
21 | console.error(e.message);
22 | }
23 | }, []);
24 | return ;
25 | };
26 |
--------------------------------------------------------------------------------
/src/models/answer/user.js:
--------------------------------------------------------------------------------
1 | import { list } from '@/services/answer/user';
2 | import { setList, removeItem } from '@/utils/model';
3 | export default {
4 | namespace: 'userAnswer',
5 |
6 | state: {},
7 |
8 | effects: {
9 | *list({ payload: { append, ...payload } }, { call, put }) {
10 | const response = yield call(list, payload);
11 | yield put({
12 | type: 'setList',
13 | payload: { append, ...(response ? response.data : {}) },
14 | });
15 | return response;
16 | },
17 | },
18 |
19 | reducers: {
20 | setList(state, { payload }) {
21 | return setList('list', payload, state);
22 | },
23 | removeItem(state, { payload }) {
24 | return removeItem('list', payload, state);
25 | },
26 | },
27 | };
28 |
--------------------------------------------------------------------------------
/src/models/question/user.js:
--------------------------------------------------------------------------------
1 | import { list } from '@/services/question/user';
2 | import { setList, removeItem } from '@/utils/model';
3 | export default {
4 | namespace: 'userQuestion',
5 |
6 | state: {},
7 |
8 | effects: {
9 | *list({ payload: { append, ...payload } }, { call, put }) {
10 | const response = yield call(list, payload);
11 | yield put({
12 | type: 'setList',
13 | payload: { append, ...(response ? response.data : {}) },
14 | });
15 | return response;
16 | },
17 | },
18 |
19 | reducers: {
20 | setList(state, { payload }) {
21 | return setList('list', payload, state);
22 | },
23 | removeItem(state, { payload }) {
24 | return removeItem('list', payload, state);
25 | },
26 | },
27 | };
28 |
--------------------------------------------------------------------------------
/src/pages/home/components/Writer/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Card } from 'antd';
3 | import { useSelector } from 'umi';
4 | import List from '@/components/List';
5 | import { UserAuthor } from '@/components/User';
6 | import Loading from '@/components/Loading';
7 |
8 | export default ({ className }) => {
9 | const dataSource = useSelector((state) => state.explore.writer);
10 |
11 | if (!dataSource) return ;
12 |
13 | const renderItem = (item) => {
14 | return (
15 |
16 |
17 |
18 | );
19 | };
20 |
21 | return (
22 |
23 |
24 |
25 | );
26 | };
27 |
--------------------------------------------------------------------------------
/src/models/article/user.js:
--------------------------------------------------------------------------------
1 | import { list, del } from '@/services/article/user';
2 | import { setList, removeItem } from '@/utils/model';
3 | export default {
4 | namespace: 'userArticle',
5 |
6 | state: {},
7 |
8 | effects: {
9 | *list({ payload: { append, ...payload } }, { call, put }) {
10 | const response = yield call(list, payload);
11 | yield put({
12 | type: 'setList',
13 | payload: { append, ...(response ? response.data : {}) },
14 | });
15 | return response;
16 | },
17 | },
18 |
19 | reducers: {
20 | setList(state, { payload }) {
21 | return setList('list', payload, state);
22 | },
23 | removeItem(state, { payload }) {
24 | return removeItem('list', payload, state);
25 | },
26 | },
27 | };
28 |
--------------------------------------------------------------------------------
/src/models/software/user.js:
--------------------------------------------------------------------------------
1 | import { list, del } from '@/services/software/user';
2 | import { setList, removeItem } from '@/utils/model';
3 | export default {
4 | namespace: 'userSoftware',
5 |
6 | state: {},
7 |
8 | effects: {
9 | *list({ payload: { append, ...payload } }, { call, put }) {
10 | const response = yield call(list, payload);
11 | yield put({
12 | type: 'setList',
13 | payload: { append, ...(response ? response.data : {}) },
14 | });
15 | return response;
16 | },
17 | },
18 |
19 | reducers: {
20 | setList(state, { payload }) {
21 | return setList('list', payload, state);
22 | },
23 | removeItem(state, { payload }) {
24 | return removeItem('list', payload, state);
25 | },
26 | },
27 | };
28 |
--------------------------------------------------------------------------------
/src/pages/home/components/Answerer/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Card } from 'antd';
3 | import { useSelector } from 'umi';
4 | import List from '@/components/List';
5 | import { UserAuthor } from '@/components/User';
6 | import Loading from '@/components/Loading';
7 |
8 | export default ({ className }) => {
9 | const dataSource = useSelector((state) => state.explore.answerer);
10 |
11 | if (!dataSource) return ;
12 |
13 | const renderItem = (item) => {
14 | return (
15 |
16 |
17 |
18 | );
19 | };
20 |
21 | return (
22 |
23 |
24 |
25 | );
26 | };
27 |
--------------------------------------------------------------------------------
/src/components/AvatarCropper/ImageCropper.less:
--------------------------------------------------------------------------------
1 | .image-cropper {
2 | display: flex;
3 | justify-content: space-between;
4 | margin-bottom: 16px;
5 |
6 | .image-cropper-tool {
7 | position: relative;
8 | overflow: hidden;
9 | width: 320px;
10 | height: 320px;
11 |
12 | > img {
13 | display: block;
14 | /* This rule is very important, please don't ignore this */
15 | max-width: 100%;
16 | }
17 | }
18 |
19 | .image-cropper-preview {
20 | font-size: 14px;
21 | color: #bfbfbf;
22 | text-align: center;
23 |
24 | .image-cropper-thumb {
25 | width: 120px;
26 | height: 120px;
27 | margin-bottom: 16px;
28 | overflow: hidden;
29 | background-color: #fafafa;
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/pages/knowledge/index.js:
--------------------------------------------------------------------------------
1 | import { Empty } from 'antd';
2 | import React from 'react';
3 |
4 | const KnowLedge = () => {
5 | return (
6 |
14 |
15 | 🚀您可以出售课程,文章,漫画,创意作品,软件,电子书,音乐,游戏,咨询等服务轻松获得收入
16 |
17 | 🚧正在施工中,敬请期待~
18 |
19 | }
20 | />
21 | );
22 | };
23 | KnowLedge.getInitialProps = async ({ isServer, store }) => {
24 | const { getState } = store;
25 |
26 | if (isServer) return getState();
27 | };
28 |
29 | export default KnowLedge;
30 |
--------------------------------------------------------------------------------
/src/pages/user/dashboard/components/Layout/Nav/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link } from 'umi';
3 | import styles from './index.less';
4 |
5 | export default ({ dataSource, defaultKey }) => {
6 | return (
7 |
8 | {dataSource.map(({ key, type, title, icon, to }, index) => {
9 | if (type === 'divider') return ;
10 | return (
11 |
16 | {icon}
17 | {title}
18 |
19 | );
20 | })}
21 |
22 | );
23 | };
24 |
--------------------------------------------------------------------------------
/src/components/Container/index.less:
--------------------------------------------------------------------------------
1 | .layout-sider.ant-menu {
2 | border: 1px solid #f0f0f0;
3 |
4 | .ant-menu-item {
5 | padding-left: 0;
6 | border-bottom: 1px solid #e8e8e8;
7 | height: 48px;
8 | line-height: 48px;
9 | color: #595959;
10 | margin-bottom: 0;
11 |
12 | > a {
13 | color: #595959;
14 | padding-left: 24px;
15 | display: block;
16 | border-left: 2px solid rgba(0, 0, 0, 0);
17 | }
18 | }
19 |
20 | .ant-menu-item.ant-menu-item-selected {
21 | background-color: transparent;
22 | > a {
23 | border-left-color: @primary-color;
24 | font-weight: 500;
25 | color: #262626;
26 | }
27 | }
28 |
29 | .ant-menu-item:not(:last-child) {
30 | margin-top: 0;
31 | margin-bottom: 0;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/components/Exception/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Result, Button } from 'antd';
3 | import { history, useIntl } from 'umi';
4 |
5 | export default ({ status = 404, title, subTitle, go }) => {
6 | const intl = useIntl();
7 | return (
8 | history.push(go || '/')}>
24 | Back Home
25 |
26 | }
27 | />
28 | );
29 | };
30 |
--------------------------------------------------------------------------------
/src/pages/path/components/column/components/member/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { useSelector } from 'umi';
3 | import Author from '@/components/User/Author';
4 |
5 | const Member = () => {
6 | const dataSource = useSelector(state => state.columnMember.list);
7 | if (!dataSource) return null;
8 | return (
9 |
10 | {dataSource.data.map(({ user }) => {
11 | return
;
12 | })}
13 |
14 | );
15 | };
16 |
17 | Member.getInitialProps = async ({ isServer, store, params }) => {
18 | const { dispatch, getState } = store;
19 |
20 | await dispatch({
21 | type: 'columnMember/list',
22 | payload: {
23 | ...params,
24 | },
25 | });
26 |
27 | if (isServer) return getState();
28 | };
29 |
30 | export default Member;
31 |
--------------------------------------------------------------------------------
/src/components/Editor/Collab/ot/client/snapshot-request/snapshot-version-request.js:
--------------------------------------------------------------------------------
1 | var SnapshotRequest = require('./snapshot-request');
2 | var util = require('../../util');
3 |
4 | module.exports = SnapshotVersionRequest;
5 |
6 | function SnapshotVersionRequest(connection, requestId, collection, id, version, callback) {
7 | SnapshotRequest.call(this, connection, requestId, collection, id, callback);
8 |
9 | if (!util.isValidVersion(version)) {
10 | throw new Error('Snapshot version must be a positive integer or null');
11 | }
12 |
13 | this.version = version;
14 | }
15 |
16 | SnapshotVersionRequest.prototype = Object.create(SnapshotRequest.prototype);
17 |
18 | SnapshotVersionRequest.prototype._message = function() {
19 | return {
20 | a: 'nf',
21 | id: this.requestId,
22 | c: this.collection,
23 | d: this.id,
24 | v: this.version,
25 | };
26 | };
27 |
--------------------------------------------------------------------------------
/src/components/User/Actors/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import UserAuthor from '../Author';
3 | import './index.less';
4 | import { Space } from 'antd';
5 | export default ({ actors = [], count, useBrand = true, ...props }) => {
6 | return (
7 |
8 |
9 | {actors.map((user, index) => {
10 | return (
11 |
12 |
13 | {index !== actors.length - 1 ? '、' : ''}
14 |
15 | );
16 | })}
17 |
18 | {count && count > actors.length && {` 等${count}人`}}
19 |
20 | );
21 | };
22 |
--------------------------------------------------------------------------------
/src/models/column/member.js:
--------------------------------------------------------------------------------
1 | import { list } from '@/services/column/member'
2 | import { setList, removeItem , replaceItem} from '@/utils/model'
3 |
4 | export default {
5 | namespace: 'columnMember',
6 |
7 | state: {},
8 |
9 | effects: {
10 | *list({ payload }, { call,put }){
11 | const response = yield call(list,payload)
12 | yield put({
13 | type: 'setList',
14 | payload: response.data
15 | })
16 | return response
17 | }
18 | },
19 |
20 | reducers:{
21 | setList(state , { payload }){
22 | return setList("list",payload,state)
23 | },
24 | removeItem(state , { payload } ){
25 | return removeItem("list",payload.id,state)
26 | },
27 | replaceItem(state , { payload } ){
28 | return replaceItem("list",payload,state)
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/src/pages/user/register/index.less:
--------------------------------------------------------------------------------
1 | .form {
2 | margin-top: 36px;
3 |
4 | .protocol {
5 | margin-top: 8px;
6 | margin-bottom: 0;
7 | color: #8c8c8c;
8 | text-align: center;
9 | }
10 |
11 | .register-footer {
12 | margin-top: 26px;
13 | text-align: center;
14 | justify-content: center;
15 | width: 100%;
16 | }
17 |
18 | .third-login {
19 | text-align: center;
20 | justify-content: center;
21 | width: 100%;
22 | margin-top: 26px;
23 | padding-top: 26px;
24 | }
25 | }
26 |
27 | .title {
28 | font-size: 32px;
29 | line-height: 1.2;
30 | color: #262626;
31 | text-align: center;
32 | margin-bottom: 24px;
33 | font-weight: 500;
34 |
35 | .sub {
36 | font-weight: normal;
37 | color: #595959;
38 | margin-top: 8px;
39 | font-size: 18px;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/pages/user/settings/account/components/Password/formMap.js:
--------------------------------------------------------------------------------
1 | import formMap from '@/components/Form/map';
2 | import { Input } from 'antd';
3 | const { Password } = formMap;
4 | export default {
5 | Password,
6 | ConfirmPassword: {
7 | component: Input.Password,
8 | props: {
9 | size: 'large',
10 | type: 'password',
11 | placeholder: '请再次输入新密码',
12 | },
13 | rules: [
14 | {
15 | required: true,
16 | message: '请再次输入新密码',
17 | },
18 | ({ getFieldValue }) => ({
19 | validator(rule, value) {
20 | if (!value || getFieldValue('password') === value) {
21 | return Promise.resolve();
22 | }
23 | return Promise.reject('两次密码输入不一致!');
24 | },
25 | }),
26 | ],
27 | },
28 | };
29 |
--------------------------------------------------------------------------------
/src/components/Container/Sider.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Menu } from 'antd';
3 | import { Link } from 'umi';
4 | import './index.less';
5 |
6 | const { Item, Divider } = Menu;
7 |
8 | function Sider({ dataSource, defaultKey, activeKey, onSelect }) {
9 | return (
10 |
25 | );
26 | }
27 | export default Sider;
28 |
--------------------------------------------------------------------------------
/src/components/Editor/Collab/ot/client/snapshot-request/snapshot-timestamp-request.js:
--------------------------------------------------------------------------------
1 | var SnapshotRequest = require('./snapshot-request');
2 | var util = require('../../util');
3 |
4 | module.exports = SnapshotTimestampRequest;
5 |
6 | function SnapshotTimestampRequest(connection, requestId, collection, id, timestamp, callback) {
7 | SnapshotRequest.call(this, connection, requestId, collection, id, callback);
8 |
9 | if (!util.isValidTimestamp(timestamp)) {
10 | throw new Error('Snapshot timestamp must be a positive integer or null');
11 | }
12 |
13 | this.timestamp = timestamp;
14 | }
15 |
16 | SnapshotTimestampRequest.prototype = Object.create(SnapshotRequest.prototype);
17 |
18 | SnapshotTimestampRequest.prototype._message = function() {
19 | return {
20 | a: 'nt',
21 | id: this.requestId,
22 | c: this.collection,
23 | d: this.id,
24 | ts: this.timestamp,
25 | };
26 | };
27 |
--------------------------------------------------------------------------------
/src/pages/user/login/formMap.js:
--------------------------------------------------------------------------------
1 | import formMap from '@/components/Form/map';
2 | import { Input } from 'antd';
3 | const { Mobile, Captcha } = formMap;
4 |
5 | export default {
6 | UserName: {
7 | props: {
8 | size: 'large',
9 | id: 'username',
10 | placeholder: '用户名 / 手机号 / 邮箱',
11 | },
12 | rules: [
13 | {
14 | required: true,
15 | message: '请输入用户名/手机号/邮箱',
16 | },
17 | ],
18 | },
19 | Password: {
20 | component: Input.Password,
21 | props: {
22 | size: 'large',
23 | type: 'password',
24 | id: 'password',
25 | placeholder: '密码',
26 | },
27 | rules: [
28 | {
29 | required: true,
30 | message: '请输入密码',
31 | },
32 | ],
33 | },
34 | Mobile,
35 | Captcha,
36 | };
37 |
--------------------------------------------------------------------------------
/src/services/question/index.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function list(params) {
4 | return request(`/api/question/list`, {
5 | params,
6 | });
7 | }
8 |
9 | export async function related(params) {
10 | return request(`/api/question/related`, {
11 | params,
12 | });
13 | }
14 |
15 | export async function find({ id, ...params }) {
16 | return request(`/api/question/${id}`, {
17 | params,
18 | });
19 | }
20 |
21 | export async function adopt({ id, ...other }) {
22 | return request(`/api/question/${id}/adopt`, {
23 | method: 'POST',
24 | data: other,
25 | });
26 | }
27 |
28 | export async function view({ id, ...params }) {
29 | return request(`/api/question/${id}/view`, {
30 | params,
31 | });
32 | }
33 |
34 | export async function del({ id }) {
35 | return request(`/api/question/${id}`, {
36 | method: 'DELETE',
37 | });
38 | }
39 |
--------------------------------------------------------------------------------
/src/components/Ad/AdSense.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useRef } from 'react';
2 |
3 | export default ({ style, slot_id, data_id, format }) => {
4 | const div = useRef();
5 | useEffect(() => {
6 | try {
7 | div.current.setAttribute('style', style);
8 | if (typeof window === 'undefined') return;
9 | (window.adsbygoogle = window.adsbygoogle || []).push({});
10 | } catch (e) {
11 | console.error(e.message);
12 | }
13 | }, []);
14 | let styleJson = {};
15 | if (style) {
16 | try {
17 | styleJson = JSON.parse(style);
18 | } catch (e) {}
19 | }
20 |
21 | return (
22 |
30 | );
31 | };
32 |
--------------------------------------------------------------------------------
/src/pages/question/Edit/components/Alert/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Alert } from 'antd';
3 | import { QuestionCircleTwoTone } from '@ant-design/icons';
4 | import styles from './index.less';
5 |
6 | export default () => {
7 | return (
8 |
14 |
15 | 让你的提问获得更多解答
16 |
17 | · 问题是什么,你想得到什么帮助,以“?”结束
18 | · 保持文字简练,表述清晰问题的关键点
19 | · 添加合适的标签,让问题更好地流通
20 |
21 | }
22 | banner
23 | closable
24 | />
25 | );
26 | };
27 |
--------------------------------------------------------------------------------
/src/pages/question/edit/components/Alert/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Alert } from 'antd';
3 | import { QuestionCircleTwoTone } from '@ant-design/icons';
4 | import styles from './index.less';
5 |
6 | export default () => {
7 | return (
8 |
14 |
15 | 让你的提问获得更多解答
16 |
17 | · 问题是什么,你想得到什么帮助,以“?”结束
18 | · 保持文字简练,表述清晰问题的关键点
19 | · 添加合适的标签,让问题更好地流通
20 |
21 | }
22 | banner
23 | closable
24 | />
25 | );
26 | };
27 |
--------------------------------------------------------------------------------
/src/layouts/BasicLayout.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Header from '@/components/Header';
3 | import BlankLayout from '@/layouts/BlankLayout';
4 | import Footer from '@/components/Footer';
5 | import { RouteContext } from '@/context';
6 |
7 | const BasicLayout = ({ route, children, ...props }) => {
8 | return (
9 |
10 |
11 | {({ isMobile }) => {
12 | return (
13 | <>
14 |
15 | {children}
16 |
17 | >
18 | );
19 | }}
20 |
21 |
22 | );
23 | };
24 |
25 | BasicLayout.getInitialProps = ctx => {
26 | BlankLayout.getInitialProps(ctx);
27 | };
28 | export default BasicLayout;
29 |
--------------------------------------------------------------------------------
/src/models/path.js:
--------------------------------------------------------------------------------
1 | import { find } from '@/services/path';
2 | export default {
3 | namespace: 'path',
4 |
5 | state: {},
6 | effects: {
7 | *find({ payload: { reducer, ...payload } }, { call, put }) {
8 | const response = yield call(find, payload);
9 | const { result, data } = response || {};
10 |
11 | if (result && reducer !== false) {
12 | yield put({
13 | type: 'setDetail',
14 | payload: data,
15 | });
16 | }
17 | return response;
18 | },
19 | },
20 | reducers: {
21 | setDetail(state, { payload }) {
22 | return {
23 | ...state,
24 | detail: { ...state.detail, ...payload },
25 | };
26 | },
27 | clearDetail(state) {
28 | return {
29 | ...state,
30 | detail: null,
31 | };
32 | },
33 | },
34 | };
35 |
--------------------------------------------------------------------------------
/src/services/article/comment.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function create({ articleId, ...other }) {
4 | return request(`/api/article/${articleId}/comment/create`, {
5 | method: 'PUT',
6 | data: other,
7 | });
8 | }
9 |
10 | export async function deleteComment({ articleId, id }) {
11 | return request(`/api/article/${articleId}/comment/${id}`, {
12 | method: 'DELETE',
13 | });
14 | }
15 |
16 | export async function getRoot({ articleId, ...params }) {
17 | return request(`/api/article/${articleId}/comment/root`, {
18 | params,
19 | });
20 | }
21 |
22 | export async function getChild({ articleId, id, ...params }) {
23 | return request(`/api/article/${articleId}/comment/${id}/child`, {
24 | params,
25 | });
26 | }
27 |
28 | export async function vote({ articleId, id, type }) {
29 | return request(`/api/article/${articleId}/comment/${id}/${type}`, {
30 | method: 'POST',
31 | });
32 | }
33 |
--------------------------------------------------------------------------------
/src/pages/article/components/HotTag/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { useSelector } from 'umi';
3 | import { Card } from 'antd';
4 | import Loading from '@/components/Loading';
5 | import Tag from '@/components/Tag';
6 | import List from '@/components/List';
7 |
8 | export default props => {
9 | const renderItem = ({ id, name }) => {
10 | return (
11 |
12 |
13 |
14 | );
15 | };
16 |
17 | const dataSource = useSelector(state => state.tag.list);
18 | if (!dataSource) return ;
19 | return (
20 |
21 |
29 |
30 | );
31 | };
32 |
--------------------------------------------------------------------------------
/src/pages/user/login/index.less:
--------------------------------------------------------------------------------
1 | .login-form {
2 | margin-top: 36px;
3 |
4 | :global {
5 | .ant-tabs-nav-list {
6 | justify-content: center;
7 | width: 100%;
8 | }
9 | }
10 |
11 | .third-login {
12 | text-align: center;
13 | justify-content: center;
14 | width: 100%;
15 | margin-top: 26px;
16 | padding-top: 26px;
17 | }
18 |
19 | .login-footer {
20 | margin-top: 26px;
21 | text-align: center;
22 | justify-content: center;
23 | width: 100%;
24 | }
25 | }
26 |
27 | .protocol {
28 | margin-top: 8px;
29 | color: #8c8c8c;
30 | text-align: center;
31 | }
32 |
33 | .title {
34 | font-size: 32px;
35 | line-height: 1.2;
36 | color: #262626;
37 | text-align: center;
38 | font-weight: 500;
39 |
40 | .sub {
41 | font-weight: normal;
42 | color: #595959;
43 | margin-top: 8px;
44 | font-size: 18px;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/components/User/Brand/index.less:
--------------------------------------------------------------------------------
1 | .user-card {
2 | width: 346px;
3 | padding: 4px 0;
4 |
5 | .body {
6 | display: flex;
7 | :global(.ant-avatar) {
8 | min-width: 48px;
9 | }
10 | .info {
11 | margin-left: 16px;
12 | word-wrap: break-word;
13 | word-break: break-all;
14 | }
15 | }
16 |
17 | .footer {
18 | display: flex;
19 | justify-content: space-between;
20 | margin: 16px -16px -4px;
21 | padding: 12px 16px 0;
22 | border-top: 1px solid #f5f5f5;
23 |
24 | .follow {
25 | display: flex;
26 | .item {
27 | margin-right: 28px;
28 | color: #bfbfbf;
29 | .count {
30 | margin-left: 8px;
31 | color: #262626;
32 | }
33 | }
34 | }
35 |
36 | .user-link {
37 | float: right;
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/components/Column/Brand/index.less:
--------------------------------------------------------------------------------
1 | .column-card {
2 | width: 346px;
3 | padding: 4px 0;
4 |
5 | .body {
6 | display: flex;
7 | :global(.ant-avatar) {
8 | min-width: 48px;
9 | }
10 | .info {
11 | margin-left: 16px;
12 | word-wrap: break-word;
13 | word-break: break-all;
14 |
15 | h2 > a {
16 | color: #262626;
17 | }
18 | }
19 | }
20 |
21 | .footer {
22 | margin-top: 16px;
23 | padding: 12px 16px 0;
24 | border-top: 1px solid #f5f5f5;
25 | text-align: center;
26 |
27 | .follow {
28 | display: flex;
29 | margin-bottom: 16px;
30 |
31 | .item {
32 | flex: 1;
33 | color: #bfbfbf;
34 |
35 | .count {
36 | display: block;
37 | color: #262626;
38 | }
39 | }
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/components/Form/Tab.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react';
2 | import { Tabs } from 'antd';
3 | import FormContext from './FormContext';
4 |
5 | const { TabPane } = Tabs;
6 |
7 | /**const generateId = (() => {
8 | let i = 0;
9 | return (prefix = '') => {
10 | i += 1;
11 | return `${prefix}${i}`;
12 | };
13 | })();**/
14 |
15 | const FormTab = props => {
16 | useEffect(() => {
17 | //const uniqueId = generateId('form-tab-');
18 | const { tabUtil } = props;
19 | if (tabUtil) {
20 | //tabUtil.addTab(uniqueId);
21 | }
22 | }, []);
23 | const { children } = props;
24 | return {props.active && children};
25 | };
26 |
27 | const WrapContext = props => (
28 |
29 | {value => }
30 |
31 | );
32 |
33 | // 标志位 用来判断是不是自定义组件
34 | WrapContext.typeName = 'FormTab';
35 |
36 | export default WrapContext;
37 |
--------------------------------------------------------------------------------
/src/services/software/comment.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function create({ softwareId, ...other }) {
4 | return request(`/api/software/${softwareId}/comment/create`, {
5 | method: 'PUT',
6 | data: other,
7 | });
8 | }
9 |
10 | export async function deleteComment({ softwareId, id }) {
11 | return request(`/api/software/${softwareId}/comment/${id}`, {
12 | method: 'DELETE',
13 | });
14 | }
15 |
16 | export async function getRoot({ softwareId, ...params }) {
17 | return request(`/api/software/${softwareId}/comment/root`, {
18 | params,
19 | });
20 | }
21 |
22 | export async function getChild({ softwareId, id, ...params }) {
23 | return request(`/api/software/${softwareId}/comment/${id}/child`, {
24 | params,
25 | });
26 | }
27 |
28 | export async function vote({ softwareId, id, type }) {
29 | return request(`/api/software/${softwareId}/comment/${id}/${type}`, {
30 | method: 'POST',
31 | });
32 | }
33 |
--------------------------------------------------------------------------------
/src/services/question/comment.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function create({ question_id, ...other }) {
4 | return request(`/api/question/${question_id}/comment/create`, {
5 | method: 'PUT',
6 | data: other,
7 | });
8 | }
9 |
10 | export async function deleteComment({ question_id, id }) {
11 | return request(`/api/question/${question_id}/comment/${id}`, {
12 | method: 'DELETE',
13 | });
14 | }
15 |
16 | export async function getRoot({ question_id, ...params }) {
17 | return request(`/api/question/${question_id}/comment/root`, {
18 | params,
19 | });
20 | }
21 |
22 | export async function getChild({ question_id, id, ...params }) {
23 | return request(`/api/question/${question_id}/comment/${id}/child`, {
24 | params,
25 | });
26 | }
27 |
28 | export async function vote({ question_id, id, type }) {
29 | return request(`/api/question/${question_id}/comment/${id}/${type}`, {
30 | method: 'POST',
31 | });
32 | }
33 |
--------------------------------------------------------------------------------
/src/services/validation.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 | import { init } from './geetest';
3 |
4 | export async function sendCaptcha({ action, ...params }) {
5 | return new Promise((resolve, reject) => {
6 | init(action)
7 | .then(({ validate, key }) => {
8 | if (!validate) return reject();
9 | request(`/api/validation/${action}/code`, {
10 | method: 'POST',
11 | data: {
12 | ...params,
13 | geetest: {
14 | key,
15 | challenge: validate.geetest_challenge,
16 | validate: validate.geetest_validate,
17 | seccode: validate.geetest_seccode,
18 | },
19 | },
20 | })
21 | .then(resolve)
22 | .catch(reject);
23 | })
24 | .catch(reject);
25 | });
26 | }
27 |
--------------------------------------------------------------------------------
/src/pages/preview/index.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react';
2 | import { useDispatch, useSelector, useHistory, useLocation } from 'umi';
3 | import Loading from '@/components/Loading';
4 | import styles from './index.less';
5 | export default () => {
6 | const dispatch = useDispatch();
7 | const location = useLocation();
8 | const history = useHistory();
9 | const { key } = location.query;
10 | if (!key) history.push('/404');
11 | useEffect(() => {
12 | dispatch({
13 | type: 'preview/getURL',
14 | payload: {
15 | key,
16 | },
17 | });
18 | }, [key, dispatch]);
19 |
20 | const fileInfo = useSelector(state => state.preview[key]);
21 | if (!fileInfo) return ;
22 | const { config, preview } = fileInfo;
23 | let url = preview;
24 | if (!config.doc) url = fileInfo.url;
25 | return (
26 |
27 |
28 |
29 | );
30 | };
31 |
--------------------------------------------------------------------------------
/src/components/Content/Answer/Action/Favorite.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { useDispatch } from 'umi';
3 | import { FavoriteButton } from '@/components/Button';
4 | import { useState } from 'react';
5 |
6 | export default ({ id, use_star, allow_star, size }) => {
7 | const dispatch = useDispatch();
8 | const [following, setFollowing] = useState(false);
9 | const [useStar, setUseStar] = useState(use_star);
10 |
11 | const onStar = () => {
12 | if (following) return;
13 | setFollowing(true);
14 | const type = !use_star ? 'follow' : 'unfollow';
15 | dispatch({
16 | type: `answerStar/${type}`,
17 | payload: {
18 | id,
19 | },
20 | }).then(() => {
21 | setUseStar(!useStar);
22 | setFollowing(false);
23 | });
24 | };
25 |
26 | return (
27 |
28 | {useStar ? '取消收藏' : '收藏'}
29 |
30 | );
31 | };
32 |
--------------------------------------------------------------------------------
/src/components/Content/Article/Action/Favorite.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { useDispatch } from 'umi';
3 | import { FavoriteButton } from '@/components/Button';
4 | import { useState } from 'react';
5 |
6 | export default ({ id, use_star, allow_star, size }) => {
7 | const dispatch = useDispatch();
8 | const [following, setFollowing] = useState(false);
9 | const [useStar, setUseStar] = useState(use_star);
10 |
11 | const onStar = () => {
12 | if (following) return;
13 | setFollowing(true);
14 | const type = !use_star ? 'follow' : 'unfollow';
15 | dispatch({
16 | type: `articleStar/${type}`,
17 | payload: {
18 | id,
19 | },
20 | }).then(() => {
21 | setUseStar(!useStar);
22 | setFollowing(false);
23 | });
24 | };
25 |
26 | return (
27 |
28 | {useStar ? '取消收藏' : '收藏'}
29 |
30 | );
31 | };
32 |
--------------------------------------------------------------------------------
/src/services/article/index.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function list(params) {
4 | return request(`/api/article/list`, {
5 | params,
6 | });
7 | }
8 |
9 | export async function related(params) {
10 | return request(`/api/article/related`, {
11 | params,
12 | });
13 | }
14 |
15 | export async function find({ id, ...params }) {
16 | return request(`/api/article/${id}`, {
17 | params,
18 | });
19 | }
20 |
21 | export async function view({ id, ...params }) {
22 | return request(`/api/article/${id}/view`, {
23 | params,
24 | });
25 | }
26 |
27 | export async function vote({ id, type }) {
28 | return request(`/api/article/${id}/${type}`, {
29 | method: 'POST',
30 | });
31 | }
32 |
33 | export async function del({ id }) {
34 | return request(`/api/article/${id}`, {
35 | method: 'DELETE',
36 | });
37 | }
38 |
39 | export async function paidread({ id }) {
40 | return request(`/api/article/${id}/paidread`, {
41 | method: 'POST',
42 | });
43 | }
44 |
--------------------------------------------------------------------------------
/src/layouts/PassportLayout.less:
--------------------------------------------------------------------------------
1 | .wrapper {
2 | padding-top: 96px;
3 | margin: 0 auto;
4 | width: 460px;
5 |
6 | .content {
7 | background-color: #fff;
8 | padding: 40px 45px 48px;
9 | border: 1px solid #e9e9e9;
10 | border-radius: 4px;
11 | }
12 | }
13 |
14 | .header {
15 | text-align: center;
16 | margin-bottom: 24px;
17 |
18 | .logo {
19 | margin-bottom: 20px;
20 |
21 | img {
22 | height: 44px;
23 | vertical-align: top;
24 | margin-right: 16px;
25 | }
26 | }
27 |
28 | a {
29 | text-decoration: none;
30 | }
31 | }
32 |
33 | @media only screen and (max-width: 575px) {
34 | :global {
35 | .main-wrapper {
36 | background-color: #fff;
37 |
38 | .layout-container {
39 | padding: 0;
40 | }
41 | }
42 | }
43 |
44 | .wrapper {
45 | width: 100%;
46 | padding: 0;
47 |
48 | .content {
49 | border: 0 none;
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/pages/User/locales/zh-CN.js:
--------------------------------------------------------------------------------
1 | export default {
2 | 'register.page': '注册',
3 | 'register.submit.text': '注册',
4 | 'register.submit.loadingText': '注册中..',
5 | 'validation.capthcha.secondText': '{s}秒',
6 | 'validation.capthcha.sendSuccess': '验证码已发送,请注意查收短信,',
7 | 'validation.capthcha.notGet': '收不到验证码?',
8 | 'register.mobile.takeUp': '手机号已被占用,请更换手机号或去',
9 |
10 | 'login.page': '登录',
11 | 'login.page.oauth': '第三方登陆验证',
12 | 'user.settings.profile': '个人信息',
13 | 'user.settings.account': '账户管理',
14 | 'user.settings.notifications': '消息管理',
15 | 'user.dashboard.recent': '最近编辑',
16 | 'user.dashboard.article': '我的文章',
17 | 'user.dashboard.question': '我的提问',
18 | 'user.dashboard.answer': '我的回答',
19 | 'user.dashboard.column': '我的专栏',
20 | 'user.dashboard.follows': '我的关注',
21 | 'user.dashboard.wallet': '我的钱包',
22 | 'user.dashboard.collections': '我的收藏',
23 | 'user.dashboard.history': '最近浏览',
24 | 'user.notifications': '通知中心',
25 | 'user.dashboard.analytics': '内容分析',
26 | 'user.dashboard.income': '收益',
27 | };
28 |
--------------------------------------------------------------------------------
/src/pages/user/locales/zh-CN.js:
--------------------------------------------------------------------------------
1 | export default {
2 | 'register.page': '注册',
3 | 'register.submit.text': '注册',
4 | 'register.submit.loadingText': '注册中..',
5 | 'validation.capthcha.secondText': '{s}秒',
6 | 'validation.capthcha.sendSuccess': '验证码已发送,请注意查收短信,',
7 | 'validation.capthcha.notGet': '收不到验证码?',
8 | 'register.mobile.takeUp': '手机号已被占用,请更换手机号或去',
9 |
10 | 'login.page': '登录',
11 | 'login.page.oauth': '第三方登陆验证',
12 | 'user.settings.profile': '个人信息',
13 | 'user.settings.account': '账户管理',
14 | 'user.settings.notifications': '消息管理',
15 | 'user.dashboard.recent': '最近编辑',
16 | 'user.dashboard.article': '我的文章',
17 | 'user.dashboard.question': '我的提问',
18 | 'user.dashboard.answer': '我的回答',
19 | 'user.dashboard.column': '我的专栏',
20 | 'user.dashboard.follows': '我的关注',
21 | 'user.dashboard.wallet': '我的钱包',
22 | 'user.dashboard.collections': '我的收藏',
23 | 'user.dashboard.history': '最近浏览',
24 | 'user.notifications': '通知中心',
25 | 'user.dashboard.analytics': '内容分析',
26 | 'user.dashboard.income': '收益',
27 | };
28 |
--------------------------------------------------------------------------------
/src/pages/Search/index.less:
--------------------------------------------------------------------------------
1 | .search-list {
2 | .menu {
3 | border-top: 1px solid #f0f0f0;
4 | border-left: 1px solid #f0f0f0;
5 | border-right: 1px solid #f0f0f0;
6 | }
7 |
8 | :global {
9 | .ant-card-bordered {
10 | border-top: 0 none;
11 |
12 | .ant-card-meta-title {
13 | font-size: 14px;
14 | line-height: 32px;
15 | color: #595959;
16 | margin-bottom: 16px;
17 | }
18 | }
19 | }
20 |
21 | .search-item {
22 | em {
23 | font-style: normal;
24 | color: #f1403c;
25 | }
26 |
27 | .search-title a {
28 | font-size: 16px;
29 | line-height: 1.6;
30 | color: #1a1a1a;
31 | }
32 |
33 | .search-content {
34 | white-space: normal;
35 | word-break: break-word;
36 | line-height: 1.6;
37 | font-size: 13px;
38 | color: #666666;
39 | max-height: 100px;
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/pages/search/index.less:
--------------------------------------------------------------------------------
1 | .search-list {
2 | .menu {
3 | border-top: 1px solid #f0f0f0;
4 | border-left: 1px solid #f0f0f0;
5 | border-right: 1px solid #f0f0f0;
6 | }
7 |
8 | :global {
9 | .ant-card-bordered {
10 | border-top: 0 none;
11 |
12 | .ant-card-meta-title {
13 | font-size: 14px;
14 | line-height: 32px;
15 | color: #595959;
16 | margin-bottom: 16px;
17 | }
18 | }
19 | }
20 |
21 | .search-item {
22 | em {
23 | font-style: normal;
24 | color: #f1403c;
25 | }
26 |
27 | .search-title a {
28 | font-size: 16px;
29 | line-height: 1.6;
30 | color: #1a1a1a;
31 | }
32 |
33 | .search-content {
34 | white-space: normal;
35 | word-break: break-word;
36 | line-height: 1.6;
37 | font-size: 13px;
38 | color: #666666;
39 | max-height: 100px;
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/access.js:
--------------------------------------------------------------------------------
1 | import { getDvaApp } from 'umi';
2 |
3 | export default () => {
4 | const { _store } = getDvaApp();
5 | const { user } = _store.getState();
6 | let me = (user || {}).me;
7 |
8 | if (!me) {
9 | if (typeof window !== 'undefined' && window.g_initialProps && window.g_initialProps.user) {
10 | me = window.g_initialProps.user.me;
11 | }
12 | if (!me)
13 | return {
14 | isLogin: false,
15 | };
16 | }
17 |
18 | const isLogin = !!me;
19 | const accessArray = me.access || [];
20 | const accessList = {};
21 | accessArray.forEach(({ name }) => {
22 | const names = name.split('_');
23 | const key = [];
24 | names.forEach(char => {
25 | if (key.length === 0) key.push(char);
26 | else {
27 | key.push(char.charAt(0).toUpperCase() + char.slice(1));
28 | }
29 | });
30 | accessList[key.join('')] = true;
31 | });
32 |
33 | return {
34 | isLogin,
35 | ...accessList,
36 | };
37 | };
38 |
--------------------------------------------------------------------------------
/src/components/Header/Search/index.less:
--------------------------------------------------------------------------------
1 | .top-search,
2 | .m-top-search {
3 | width: 200px;
4 |
5 | .input {
6 | border: none;
7 | outline: none;
8 | box-shadow: none;
9 | background: #f5f5f5;
10 | border-radius: 4px;
11 |
12 | :global {
13 | .ant-input-group-addon {
14 | color: #8c8c8c;
15 | background: transparent;
16 | border: 0 none;
17 |
18 | .ant-input-search-button,
19 | .ant-input-search-button:hover {
20 | background: transparent;
21 | border: 0 none;
22 | }
23 | }
24 |
25 | .ant-input {
26 | background: #f5f5f5;
27 | border: none;
28 | outline: none;
29 | box-shadow: none;
30 | }
31 |
32 | .ant-input-search-icon::before {
33 | border: 0 none;
34 | }
35 | }
36 | }
37 | }
38 |
39 | .m-top-search {
40 | width: 100%;
41 | margin: 0;
42 | }
43 |
--------------------------------------------------------------------------------
/src/components/Button/index.less:
--------------------------------------------------------------------------------
1 | .button:global(.ant-btn-ghost),
2 | .button[disabled],
3 | .button[disabled]:hover,
4 | .button[disabled]:focus {
5 | background-color: transparent !important;
6 | }
7 |
8 | .button:global(:not(.ant-btn-primary)) {
9 | padding: 0;
10 |
11 | :global {
12 | .anticon {
13 | + span {
14 | margin-left: 4px;
15 | }
16 | }
17 | span {
18 | + .anticon {
19 | margin-left: 4px;
20 | }
21 | }
22 | }
23 | }
24 |
25 | .button:not([disabled]):global(:not(.ant-btn-primary)),
26 | .button:focus:global(:not(.ant-btn-primary)) {
27 | color: #595959;
28 | }
29 |
30 | .button:not([disabled]):global(:not(.ant-btn-primary)).active {
31 | color: @primary-color;
32 | }
33 |
34 | .button:not([disabled]):global(:not(.ant-btn-primary)):hover {
35 | background-image: none;
36 | color: @primary-color;
37 | }
38 |
39 | .button[ant-click-animating-without-extra-node]:after {
40 | border: 0 none;
41 | opacity: 0;
42 | animation: none 0 ease 0 1 normal;
43 | }
44 |
--------------------------------------------------------------------------------
/src/components/Content/Question/Action/Favorite.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { message } from 'antd';
3 | import { useDispatch, useSelector } from 'umi';
4 | import { FavoriteButton } from '@/components/Button';
5 |
6 | export default ({ id, use_star, allow_star, ...props }) => {
7 | const dispatch = useDispatch();
8 | const [following, setFollowing] = useState(false);
9 | const me = useSelector(state => state.user.me);
10 | const onStar = () => {
11 | if (!me) return message.error('未登录');
12 | if (following) return;
13 | setFollowing(true);
14 | const type = !use_star ? 'follow' : 'unfollow';
15 | dispatch({
16 | type: `questionStar/${type}`,
17 | payload: {
18 | id,
19 | },
20 | }).then(() => {
21 | setFollowing(false);
22 | });
23 | };
24 |
25 | return (
26 |
27 | {use_star ? '取消关注' : '关注问题'}
28 |
29 | );
30 | };
31 |
--------------------------------------------------------------------------------
/src/components/Column/Star/index.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { useDispatch } from 'umi';
3 | import { Button, message } from 'antd';
4 |
5 | export default ({ id, use_star, text, ...props }) => {
6 | const [loading, setLoading] = useState(false);
7 | text = text || '关注';
8 | const dispatch = useDispatch();
9 |
10 | const onStar = () => {
11 | if (loading) return;
12 | setLoading(true);
13 | const type = use_star === false ? 'follow' : 'unfollow';
14 | dispatch({
15 | type: `columnStar/${type}`,
16 | payload: {
17 | id,
18 | },
19 | }).then((res) => {
20 | setLoading(false);
21 | if (!res.result && res.message) message.error(res.message);
22 | });
23 | };
24 |
25 | return (
26 |
34 | );
35 | };
36 |
--------------------------------------------------------------------------------
/src/components/Content/Answer/Action/Adopt.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { AdoptButton } from '@/components/Button';
3 | import { useDispatch } from 'umi';
4 |
5 | export default ({ id, question_id, allow_adopt, adopted, size = 'small' }) => {
6 | const [adopting, setAdopting] = useState(false);
7 | const dispatch = useDispatch();
8 |
9 | const doAdopt = () => {
10 | if (adopting || adopted) return;
11 | setAdopting(true);
12 | dispatch({
13 | type: 'question/adopt',
14 | payload: {
15 | id: question_id,
16 | answer_id: id,
17 | },
18 | }).then(() => {
19 | //setAdopting(false);
20 | });
21 | };
22 | if (!allow_adopt && !adopted) return null;
23 |
24 | return (
25 |
32 | {adopted ? '已采纳' : '采纳答案'}
33 |
34 | );
35 | };
36 |
--------------------------------------------------------------------------------
/src/pages/path/components/user/menu.js:
--------------------------------------------------------------------------------
1 | import Activity from './components/Activity'
2 | import Answer from './components/Answer'
3 | import Question from './components/Question'
4 | import Article from './components/Article'
5 | import Column from './components/Column'
6 | import Follows from './components/Follows'
7 | import Follower from './components/Follower'
8 |
9 | export default [
10 | {
11 | key:"activity",
12 | title:"动态",
13 | component:Activity
14 | },
15 | {
16 | key:"answer",
17 | title:"回答",
18 | component:Answer
19 | },
20 | {
21 | key:"question",
22 | title:"问题",
23 | component:Question
24 | },
25 | {
26 | key:"article",
27 | title:"文章",
28 | component:Article
29 | },
30 | {
31 | key:"column",
32 | title:"专栏",
33 | component:Column
34 | },
35 | {
36 | key:"follows",
37 | title:"关注了",
38 | component:Follows
39 | },
40 | {
41 | key:"follower",
42 | title:"关注者",
43 | component:Follower
44 | }
45 | ]
--------------------------------------------------------------------------------
/src/components/Header/Search/index.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import { Input } from 'antd';
3 | import { history } from 'umi';
4 | import styles from './index.less';
5 |
6 | const { Search } = Input;
7 | function TopSearch({ defaultValue, type, isMobile, ...props }) {
8 | const [word, setWord] = useState(defaultValue || '');
9 | const onSearch = value => {
10 | if (props.onSearch) props.onSearch(value);
11 | if (value.trim() === '') return history.push('/');
12 | history.push(`/search?q=${value}${type ? `&t=${type}` : ''}`);
13 | };
14 |
15 | useEffect(() => {
16 | setWord(defaultValue);
17 | }, [defaultValue]);
18 |
19 | return (
20 |
21 | setWord(e.target.value)}
26 | onSearch={onSearch}
27 | />
28 |
29 | );
30 | }
31 | export default TopSearch;
32 |
--------------------------------------------------------------------------------
/src/pages/user/dashboard/wallet/components/Access/Withdraw/index.less:
--------------------------------------------------------------------------------
1 | .withdraw-content {
2 | margin: 16px auto;
3 |
4 | .title {
5 | font-size: 14px;
6 | }
7 |
8 | .amount {
9 | width: 100%;
10 | color: rgba(0, 0, 0, 0.85);
11 | font-size: 24px;
12 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,
13 | 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
14 | 'Noto Color Emoji';
15 | border-top: 0 none;
16 | border-left: 0 none;
17 | border-right: 0 none;
18 | outline: none;
19 | box-shadow: none;
20 | border-radius: 0;
21 |
22 | :global(.ant-input-number-input) {
23 | height: 48px;
24 | padding: 0;
25 | }
26 |
27 | :global(.ant-input-number-handler-wrap) {
28 | display: none;
29 | }
30 | }
31 |
32 | .amount:hover,
33 | .amount:focus {
34 | box-shadow: none;
35 | }
36 | }
37 |
38 | .error {
39 | color: red;
40 | margin-bottom: 0;
41 | }
42 |
--------------------------------------------------------------------------------
/src/components/Button/index.js:
--------------------------------------------------------------------------------
1 | import BaseButton from './BaseButton';
2 | import SupportButton from './SupportButton';
3 | import OpposeButton from './OpposeButton';
4 | import DeleteButton from './DeleteButton';
5 | import ReplyButton from './ReplyButton';
6 | import ReportButton from './ReportButton';
7 | import ShareButton from './ShareButton';
8 | import CommentButton from './CommentButton';
9 | import FavoriteButton from './FavoriteButton';
10 | import EllipsisButton from './EllipsisButton';
11 | import AdoptButton from './AdoptButton';
12 | import EditButton from './EditButton';
13 | import HistoryButton from './HistoryButton';
14 | import BackTopButton from './BackTopButton';
15 | import { RewardButton, RewardPanel } from './RewardButton';
16 |
17 | export default BaseButton;
18 | export {
19 | SupportButton,
20 | OpposeButton,
21 | DeleteButton,
22 | ReplyButton,
23 | ReportButton,
24 | ShareButton,
25 | CommentButton,
26 | FavoriteButton,
27 | EllipsisButton,
28 | AdoptButton,
29 | EditButton,
30 | HistoryButton,
31 | BackTopButton,
32 | RewardButton,
33 | RewardPanel,
34 | };
35 |
--------------------------------------------------------------------------------
/src/services/user/index.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function queryName(params) {
4 | return request('/api/user/query/name', {
5 | method: 'POST',
6 | data: params,
7 | });
8 | }
9 |
10 | export async function find({ id, ...params }) {
11 | return request(`/api/user/${id}`, {
12 | params,
13 | });
14 | }
15 |
16 | export async function profile(params) {
17 | return request('/api/user/profile', {
18 | method: 'PUT',
19 | data: params,
20 | });
21 | }
22 |
23 | export async function update({ action, ...params }) {
24 | return request(`/api/user/update/${action}`, {
25 | method: 'PUT',
26 | data: params,
27 | });
28 | }
29 |
30 | export async function fetchMe(params) {
31 | return request('/api/user/me', {
32 | params,
33 | });
34 | }
35 |
36 | export async function fetchAccount(params) {
37 | return request('/api/user/account', {
38 | params,
39 | });
40 | }
41 |
42 | export async function logout(params) {
43 | return request('/api/user/logout', {
44 | params,
45 | });
46 | }
47 |
--------------------------------------------------------------------------------
/src/components/Container/Layout.js:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react';
2 | import { Row, Col } from 'antd';
3 | import { RouteContext } from '@/context';
4 |
5 | function Layout({ spans = 17, gutter = 10, children }) {
6 | const spanData = 24;
7 |
8 | if (!Array.isArray(spans)) spans = [spans, spanData - spans];
9 |
10 | const childLength = React.Children.toArray(children).length;
11 | if (childLength < 2) return children;
12 | if (childLength != spans.length) {
13 | spans = [];
14 | for (let i = 0; i < childLength; i++) {
15 | spans[i] = spanData / childLength;
16 | }
17 | }
18 | const { isMobile } = useContext(RouteContext);
19 | if (isMobile) return React.Children.toArray(children)[0];
20 | return (
21 |
22 | {React.Children.map(children, (child, index) => {
23 | return (
24 |
25 | {child}
26 |
27 | );
28 | })}
29 |
30 | );
31 | }
32 |
33 | export default Layout;
34 |
--------------------------------------------------------------------------------
/src/pages/Column/index.less:
--------------------------------------------------------------------------------
1 | .item-card {
2 | text-align: center;
3 |
4 | .title {
5 | margin-top: 20px;
6 | height: 22px;
7 | line-height: 22px;
8 | font-size: 16px;
9 | white-space: nowrap;
10 | overflow: hidden;
11 | text-overflow: ellipsis;
12 | font-weight: 600;
13 |
14 | a {
15 | color: #262626;
16 | }
17 | }
18 |
19 | .data {
20 | margin-top: 4px;
21 | height: 17px;
22 | line-height: 17px;
23 | font-size: 12px;
24 | color: #999;
25 |
26 | span + span:before {
27 | content: '\B7';
28 | margin: 0 3px;
29 | }
30 | }
31 |
32 | .description {
33 | margin-top: 20px;
34 | height: 40px;
35 | line-height: 20px;
36 | font-size: 14px;
37 | color: #444;
38 | text-overflow: ellipsis;
39 | overflow: hidden;
40 | }
41 |
42 | .to-btn {
43 | margin-top: 20px;
44 | }
45 | }
46 |
47 | .column-action {
48 | text-align: center;
49 |
50 | button {
51 | margin-right: 20px;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/pages/column/index.less:
--------------------------------------------------------------------------------
1 | .item-card {
2 | text-align: center;
3 |
4 | .title {
5 | margin-top: 20px;
6 | height: 22px;
7 | line-height: 22px;
8 | font-size: 16px;
9 | white-space: nowrap;
10 | overflow: hidden;
11 | text-overflow: ellipsis;
12 | font-weight: 600;
13 |
14 | a {
15 | color: #262626;
16 | }
17 | }
18 |
19 | .data {
20 | margin-top: 4px;
21 | height: 17px;
22 | line-height: 17px;
23 | font-size: 12px;
24 | color: #999;
25 |
26 | span + span:before {
27 | content: '\B7';
28 | margin: 0 3px;
29 | }
30 | }
31 |
32 | .description {
33 | margin-top: 20px;
34 | height: 40px;
35 | line-height: 20px;
36 | font-size: 14px;
37 | color: #444;
38 | text-overflow: ellipsis;
39 | overflow: hidden;
40 | }
41 |
42 | .to-btn {
43 | margin-top: 20px;
44 | }
45 | }
46 |
47 | .column-action {
48 | text-align: center;
49 |
50 | button {
51 | margin-right: 20px;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/pages/column/apply/formMap.js:
--------------------------------------------------------------------------------
1 | import { Input } from 'antd';
2 | import { Selector } from '@/components/Tag';
3 |
4 | export default {
5 | Name: {
6 | props: {
7 | placeholder: '专栏名称',
8 | },
9 | rules: [
10 | {
11 | required: true,
12 | message: '专栏名称不可以为空',
13 | },
14 | {
15 | min: 2,
16 | max: 60,
17 | message: '长度为2-60个字符',
18 | },
19 | ],
20 | },
21 | Tags: {
22 | component: Selector,
23 | props: {},
24 | rules: [
25 | {
26 | required: true,
27 | message: '请选择关联标签',
28 | },
29 | ],
30 | },
31 | Desc: {
32 | component: Input.TextArea,
33 | props: {
34 | autoSize: { minRows: 4, maxRows: 8 },
35 | maxLength: 200,
36 | placeholder: '专栏简介,不超过 200 字',
37 | },
38 | rules: [
39 | {
40 | required: true,
41 | message: '请输入简介,不超过 200 字',
42 | },
43 | ],
44 | },
45 | };
46 |
--------------------------------------------------------------------------------
/src/services/answer/comment.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function create({ question_id, answer_id, ...other }) {
4 | return request(`/api/question/${question_id}/answer/${answer_id}/comment/create`, {
5 | method: 'PUT',
6 | data: other,
7 | });
8 | }
9 |
10 | export async function deleteComment({ question_id, answer_id, id }) {
11 | return request(`/api/question/${question_id}/answer/${answer_id}/comment/${id}`, {
12 | method: 'DELETE',
13 | });
14 | }
15 |
16 | export async function getRoot({ question_id, answer_id, ...params }) {
17 | return request(`/api/question/${question_id}/answer/${answer_id}/comment/root`, {
18 | params,
19 | });
20 | }
21 |
22 | export async function getChild({ question_id, answer_id, id, ...params }) {
23 | return request(`/api/question/${question_id}/answer/${answer_id}/comment/${id}/child`, {
24 | params,
25 | });
26 | }
27 |
28 | export async function vote({ question_id, answer_id, id, type }) {
29 | return request(`/api/question/${question_id}/answer/${answer_id}/comment/${id}/${type}`, {
30 | method: 'POST',
31 | });
32 | }
33 |
--------------------------------------------------------------------------------
/src/layouts/PassportLayout.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link } from 'umi';
3 | import classNames from 'classnames';
4 | import Container from '@/components/Container';
5 | import BlankLayout from '@/layouts/BlankLayout';
6 | import logo from '@/assets/logo.svg';
7 | import styles from './PassportLayout.less';
8 |
9 | function PassportLayout({ route, children }) {
10 | const layout = (
11 |
12 |
13 |
14 |
15 |

16 |
17 |
18 |
19 | {children}
20 |
21 | );
22 |
23 | return (
24 |
25 |
26 | {layout}
27 |
28 |
29 | );
30 | }
31 |
32 | PassportLayout.getInitialProps = ctx => {
33 | BlankLayout.getInitialProps(ctx);
34 | };
35 | export default PassportLayout;
36 |
--------------------------------------------------------------------------------
/src/components/Header/User/ActionMenu.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Menu, Popover } from 'antd';
3 | import { Link } from 'umi';
4 | import { EditTwoTone, QuestionCircleTwoTone, PlusOutlined } from '@ant-design/icons';
5 | import styles from './index.less';
6 |
7 | export default () => {
8 | const menu = (
9 |
23 | );
24 |
25 | return (
26 |
32 |
35 |
36 | );
37 | };
38 |
--------------------------------------------------------------------------------
/src/components/Tag/Star/index.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { useDispatch } from 'umi';
3 | import { StarOutlined } from '@ant-design/icons';
4 | import { Button, message } from 'antd';
5 |
6 | export default ({ id, name, use_star, ...props }) => {
7 | const dispatch = useDispatch();
8 | const [loading, setLoading] = useState(false);
9 |
10 | const onStar = () => {
11 | if (loading) return;
12 | setLoading(true);
13 | const type = use_star ? 'unfollow' : 'follow';
14 | dispatch({
15 | type: `tagStar/${type}`,
16 | payload: {
17 | id,
18 | name,
19 | },
20 | }).then(res => {
21 | setLoading(false);
22 | if (!res.result) message.error(res.message);
23 | });
24 | };
25 |
26 | return (
27 | }
29 | loading={loading}
30 | type={use_star === true ? 'primary' : 'default'}
31 | onClick={onStar}
32 | {...props}
33 | >
34 | {use_star === true ? '已关注' : '关注'}
35 |
36 | );
37 | };
38 |
--------------------------------------------------------------------------------
/src/components/Editor/Collab/constant/index.js:
--------------------------------------------------------------------------------
1 | export const EVENT = {
2 | inactive: 'inactive',
3 | error: 'error',
4 | usersChange: 'usersChange',
5 | saving: 'saving',
6 | saved: 'saved',
7 | published: 'published',
8 | reverted: 'reverted',
9 | broadcast: 'broadcast',
10 | statusChange: 'statusChange',
11 | };
12 |
13 | export const ERROR_CODE = {
14 | INIT_FAILED: 'INIT_FAILED',
15 | SAVE_FAILED: 'SAVE_FAILED',
16 | PUBLISH_FAILED: 'PUBLISH_FAILED',
17 | DISCONNECTED: 'DISCONNECTED',
18 | STATUS_CODE: {
19 | TIMEOUT: 4001,
20 | FORCE_DISCONNECTED: 4002,
21 | },
22 | CONNECTION_ERROR: 'CONNECTION_ERROR',
23 | COLLAB_DOC_ERROR: 'COLLAB_DOC_ERROR',
24 | };
25 |
26 | export const ERROR_LEVEL = {
27 | FATAL: 'FATAL',
28 | WARNING: 'WARNING',
29 | NOTICE: 'NOTICE',
30 | };
31 |
32 | export const STATUS = {
33 | initialize: 'initialize',
34 | docLoaded: 'docLoaded',
35 | active: 'active',
36 | exit: 'exit',
37 | error: 'error',
38 | deleted: 'deleted',
39 | };
40 |
41 | export const MESSAGE = {
42 | DOC_PUBLISHED: 'DOC_PUBLISHED',
43 | DOC_DELETED: 'DOC_DELETED',
44 | };
45 |
--------------------------------------------------------------------------------
/src/pages/software/edit/components/Group/index.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react';
2 | import { useSelector, useDispatch } from 'umi';
3 | import { Select } from 'antd';
4 | import Loading from '@/components/Loading';
5 | import styles from './index.less';
6 |
7 | export default ({ value, onChange }) => {
8 | onChange = onChange || function () {};
9 |
10 | const dispatch = useDispatch();
11 |
12 | const dataSource = useSelector((state) => state.softwareGroup.list);
13 |
14 | useEffect(() => {
15 | dispatch({
16 | type: 'softwareGroup/list',
17 | payload: {},
18 | });
19 | }, [dispatch]);
20 |
21 | const renderGroup = () => {
22 | if (!dataSource || !dataSource.data) return ;
23 | return (
24 |
31 | );
32 | };
33 |
34 | return renderGroup();
35 | };
36 |
--------------------------------------------------------------------------------
/src/services/tag/index.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function create(params) {
4 | return request('/api/tag/create', {
5 | method: 'POST',
6 | data: params,
7 | });
8 | }
9 |
10 | export async function search(params) {
11 | return request(`/api/tag/search`, {
12 | params,
13 | });
14 | }
15 |
16 | export async function query(params) {
17 | return request(`/api/tag/query`, {
18 | params,
19 | });
20 | }
21 |
22 | export async function group(params) {
23 | return request('/api/tag/group', {
24 | params,
25 | });
26 | }
27 |
28 | export async function list(params) {
29 | return request(`/api/tag/list`, {
30 | params,
31 | });
32 | }
33 |
34 | export async function find({ id, ...params }) {
35 | return request(`/api/tag/${id}`, {
36 | params,
37 | });
38 | }
39 |
40 | export async function auditList(params) {
41 | return request(`/api/tag/audit-list`, {
42 | params,
43 | });
44 | }
45 |
46 | export async function auditVersion(params) {
47 | return request(`/api/tag-version/audit`, {
48 | method: 'POST',
49 | data: params,
50 | });
51 | }
52 |
--------------------------------------------------------------------------------
/src/components/List/More.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import List from './Default';
3 | import Loading, { LoadingButton } from '../Loading';
4 |
5 | const More = ({ dataSource, offset, limit, onChange, ...props }) => {
6 | offset = offset || 0;
7 | limit = limit || 20;
8 |
9 | const [loading, setLoading] = useState(false);
10 | onChange =
11 | onChange ||
12 | function() {
13 | setLoading(false);
14 | };
15 |
16 | useEffect(() => {
17 | setLoading(false);
18 | }, [dataSource]);
19 |
20 | if (!dataSource || !dataSource.data) return ;
21 |
22 | return (
23 |
24 |
25 | {dataSource && !dataSource.end && (
26 | {
29 | setLoading(true);
30 | onChange((offset += limit), limit);
31 | }}
32 | />
33 | )}
34 |
35 | );
36 | };
37 |
38 | More.Item = List.Item;
39 | export default More;
40 |
--------------------------------------------------------------------------------
/src/models/doc/version.js:
--------------------------------------------------------------------------------
1 | import { list, find, diff } from '@/services/doc/version';
2 |
3 | export default {
4 | namespace: 'version',
5 |
6 | state: {
7 | list: [],
8 | },
9 |
10 | effects: {
11 | *list({ payload }, { call, put }) {
12 | const response = yield call(list, payload);
13 | if (response.result) {
14 | yield put({
15 | type: 'updateVersions',
16 | payload: response.data,
17 | });
18 | }
19 | return response;
20 | },
21 | *find({ payload }, { call }) {
22 | const response = yield call(find, payload);
23 | if (response.result) {
24 | return response;
25 | }
26 | return response;
27 | },
28 | *diff({ payload }, { call }) {
29 | const response = yield call(diff, payload);
30 | return response;
31 | },
32 | },
33 |
34 | reducers: {
35 | updateVersions(state, { payload }) {
36 | return {
37 | ...state,
38 | list: payload,
39 | };
40 | },
41 | },
42 | };
43 |
--------------------------------------------------------------------------------
/src/components/Content/Article/Action/Delete.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { DeleteButton } from '@/components/Button';
3 | import { Modal } from 'antd';
4 | import { useDispatch } from 'umi';
5 | import { ExclamationCircleOutlined } from '@ant-design/icons';
6 |
7 | export default ({ id, title, callback, ...props }) => {
8 | const dispatch = useDispatch();
9 |
10 | const onDelete = () => {
11 | Modal.confirm({
12 | title: `确定删除 ${title || ''}?`,
13 | okText: '确定',
14 | cancelText: '取消',
15 | centered: true,
16 | icon: ,
17 | onOk() {
18 | return new Promise(resolve => {
19 | dispatch({
20 | type: 'article/delete',
21 | payload: {
22 | id,
23 | },
24 | }).then(res => {
25 | resolve();
26 | if (callback) callback(res);
27 | });
28 | });
29 | },
30 | onCancel() {},
31 | });
32 | };
33 |
34 | return ;
35 | };
36 |
--------------------------------------------------------------------------------
/src/pages/user/dashboard/history/index.less:
--------------------------------------------------------------------------------
1 | .history-list {
2 | .history-item {
3 | .time {
4 | position: relative;
5 | display: block;
6 | font-size: 14px;
7 | font-weight: 600;
8 | color: #262626;
9 | padding-top: 16px;
10 | padding-bottom: 16px;
11 | border-bottom: 1px solid #f0f0f0;
12 | background: #ffffff;
13 | }
14 |
15 | .content {
16 | padding: 12px 8px;
17 | display: flex;
18 | align-items: center;
19 | justify-content: space-between;
20 | border-bottom: 1px dashed #f0f0f0;
21 |
22 | > h2 {
23 | font-size: 14px;
24 | font-weight: normal;
25 | margin: 0;
26 |
27 | a {
28 | color: #595959;
29 | }
30 | }
31 | }
32 |
33 | .content:hover {
34 | background: #f5f5f5;
35 | }
36 | }
37 |
38 | .history-item:global(.ant-list-item) {
39 | padding: 0;
40 | }
41 |
42 | .history-item:first-child {
43 | .time {
44 | padding-top: 0;
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/pages/Tag/list/index.less:
--------------------------------------------------------------------------------
1 | .tag-list {
2 | margin-top: 20px;
3 | padding: 0;
4 |
5 | :global {
6 | .ant-list-item {
7 | margin-bottom: 24px;
8 | }
9 | }
10 |
11 | .tag-list-meta {
12 | margin-bottom: 20px;
13 | }
14 |
15 | .tag-card {
16 | padding: 16px;
17 |
18 | :global {
19 | .ant-card-body {
20 | padding: 0;
21 | }
22 |
23 | .ant-card-meta-title {
24 | font-size: 18px;
25 | }
26 | }
27 |
28 | .description {
29 | min-height: 110px;
30 | }
31 |
32 | .footer {
33 | margin-top: 20px;
34 | padding: 12px 0;
35 | border-top: 1px solid #f5f5f5;
36 | text-align: center;
37 |
38 | .follow {
39 | display: flex;
40 | margin-bottom: 16px;
41 |
42 | .item {
43 | color: #bfbfbf;
44 | flex: 1;
45 |
46 | .count {
47 | display: block;
48 | color: #262626;
49 | }
50 | }
51 | }
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/pages/software/detail/components/Action/Delete.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { DeleteButton } from '@/components/Button';
3 | import { Modal } from 'antd';
4 | import { useDispatch } from 'umi';
5 | import { ExclamationCircleOutlined } from '@ant-design/icons';
6 |
7 | export default ({ id, title, callback, ...props }) => {
8 | const dispatch = useDispatch();
9 |
10 | const onDelete = () => {
11 | Modal.confirm({
12 | title: `确定删除 ${title || ''}?`,
13 | okText: '确定',
14 | cancelText: '取消',
15 | centered: true,
16 | icon: ,
17 | onOk() {
18 | return new Promise((resolve) => {
19 | dispatch({
20 | type: 'software/delete',
21 | payload: {
22 | id,
23 | },
24 | }).then((res) => {
25 | resolve();
26 | if (callback) callback(res);
27 | });
28 | });
29 | },
30 | onCancel() {},
31 | });
32 | };
33 |
34 | return ;
35 | };
36 |
--------------------------------------------------------------------------------
/src/pages/tag/list/index.less:
--------------------------------------------------------------------------------
1 | .tag-list {
2 | margin-top: 20px;
3 | padding: 0;
4 |
5 | :global {
6 | .ant-list-item {
7 | margin-bottom: 24px;
8 | }
9 | }
10 |
11 | .tag-list-meta {
12 | margin-bottom: 20px;
13 | }
14 |
15 | .tag-card {
16 | padding: 16px;
17 |
18 | :global {
19 | .ant-card-body {
20 | padding: 0;
21 | }
22 |
23 | .ant-card-meta-title {
24 | font-size: 18px;
25 | }
26 | }
27 |
28 | .description {
29 | min-height: 110px;
30 | }
31 |
32 | .footer {
33 | margin-top: 20px;
34 | padding: 12px 0;
35 | border-top: 1px solid #f5f5f5;
36 | text-align: center;
37 |
38 | .follow {
39 | display: flex;
40 | margin-bottom: 16px;
41 |
42 | .item {
43 | color: #bfbfbf;
44 | flex: 1;
45 |
46 | .count {
47 | display: block;
48 | color: #262626;
49 | }
50 | }
51 | }
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/components/AvatarCropper/index.less:
--------------------------------------------------------------------------------
1 | .profile-avatar {
2 | display: flex;
3 |
4 | .upload-area {
5 | position: relative;
6 | width: 58px;
7 | height: 58px;
8 | border-radius: 58px;
9 | border: 1px solid rgba(0, 0, 0, 0);
10 | background-size: cover;
11 | background-repeat: no-repeat;
12 | background-position: 50%;
13 |
14 | > img {
15 | width: 100%;
16 | }
17 |
18 | :global {
19 | .ant-upload-drag {
20 | position: absolute;
21 | background: rgba(0, 0, 0, 0) !important;
22 | top: 0;
23 | left: 0;
24 | width: 100%;
25 | height: 100%;
26 | border-color: transparent;
27 | border-radius: 28px;
28 | }
29 |
30 | .ant-upload-drag:hover {
31 | border-color: @primary-color;
32 | }
33 | }
34 | }
35 |
36 | .upload-btn {
37 | margin-left: 20px;
38 | line-height: 1.5;
39 |
40 | > p {
41 | margin: 0;
42 | color: #8c8c8c;
43 | font-size: 12px;
44 | margin-top: 9px;
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/models/user/bank.js:
--------------------------------------------------------------------------------
1 | import { info, log } from '@/services/user/bank';
2 | import { setList } from '@/utils/model';
3 | export default {
4 | namespace: 'bank',
5 |
6 | state: {},
7 | effects: {
8 | *info({ payload }, { call, put }) {
9 | const response = yield call(info, payload);
10 | const { result, data } = response || {};
11 | if (result) {
12 | yield put({
13 | type: 'setDetail',
14 | payload: data,
15 | });
16 | }
17 | return response;
18 | },
19 | *log({ payload: { append, ...payload } }, { call, put }) {
20 | const response = yield call(log, payload);
21 | yield put({
22 | type: 'setList',
23 | payload: { ...(response.data || {}), append },
24 | });
25 | },
26 | },
27 | reducers: {
28 | setDetail(state, { payload }) {
29 | return {
30 | ...state,
31 | detail: { ...state.detail, ...payload },
32 | };
33 | },
34 | setList(state, { payload }) {
35 | return setList('list', payload, state);
36 | },
37 | },
38 | };
39 |
--------------------------------------------------------------------------------
/src/pages/user/dashboard/analytics/components/Content/index.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { Card } from 'antd';
3 | import Group from './Group';
4 | import Single from './Single';
5 | import styles from './index.less';
6 |
7 | const Content = ({ type }) => {
8 | const [key, setKey] = useState('all');
9 |
10 | const typeText = type === 'answer' ? '回答' : '文章';
11 |
12 | const tabList = [
13 | {
14 | key: 'all',
15 | tab: `所有${typeText}`,
16 | },
17 | {
18 | key: 'single',
19 | tab: `单篇${typeText}`,
20 | },
21 | ];
22 |
23 | const contentList = {
24 | all: ,
25 | single: ,
26 | };
27 |
28 | return (
29 | setKey(key)}
32 | className={styles['card-content']}
33 | >
34 | {contentList[key]}
35 |
36 | );
37 | };
38 | Content.getInitialProps = async ({ isServer, store, params }) => {
39 | const { getState } = store;
40 | await Group.getInitialProps({ isServer, store, params });
41 | if (isServer) return getState();
42 | };
43 |
44 | export default Content;
45 |
--------------------------------------------------------------------------------
/src/pages/article/components/HotColumn/index.less:
--------------------------------------------------------------------------------
1 | .hot-item {
2 | display: flex;
3 | align-items: center;
4 |
5 | .avatar {
6 | margin-right: 12px;
7 | }
8 |
9 | .info {
10 | .title {
11 | font-size: 16px;
12 | line-height: 22px;
13 | color: #000;
14 | font-weight: 400;
15 | white-space: nowrap;
16 | overflow: hidden;
17 | text-overflow: ellipsis;
18 | margin: 0;
19 |
20 | a {
21 | color: #262626;
22 | }
23 | }
24 |
25 | .data {
26 | > span {
27 | color: #999;
28 | }
29 |
30 | > span:before {
31 | content: '';
32 | position: relative;
33 | top: -1px;
34 | display: inline-block;
35 | vertical-align: middle;
36 | overflow: hidden;
37 | margin: 0 8px;
38 | width: 2px;
39 | height: 2px;
40 | border-radius: 50%;
41 | background: #999;
42 | }
43 |
44 | > span:first-child:before {
45 | display: none;
46 | }
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/components/Comment/Detail.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Loading from '../Loading';
3 | import Item from './Item';
4 | import Comment from './index';
5 | import styles from './index.less';
6 |
7 | function CommentDetail({ dataSource, onDelete, onCreate, onVote, onChange, ...props }) {
8 | if (!dataSource) return ;
9 | const { detail, ...data } = dataSource;
10 | return (
11 |
20 | }
21 | title={detail.comment_count + '条评论'}
22 | dataSource={data}
23 | onChange={onChange}
24 | onDelete={onDelete}
25 | onCreate={onCreate}
26 | onVote={onVote}
27 | scroll={true}
28 | {...props}
29 | />
30 |
31 | );
32 | }
33 | export default CommentDetail;
34 |
--------------------------------------------------------------------------------
/src/components/User/Star/index.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react';
2 | import { useDispatch } from 'umi';
3 | import { Button, message } from 'antd';
4 |
5 | export default ({ id, use_star, text, ...props }) => {
6 | const [loading, setLoading] = useState(false);
7 | const [star, setStar] = useState(use_star);
8 |
9 | useEffect(() => {
10 | setStar(use_star);
11 | }, [use_star]);
12 |
13 | text = text || '关注';
14 | const dispatch = useDispatch();
15 |
16 | const onStar = () => {
17 | if (loading) return;
18 | setLoading(true);
19 | const type = star === false ? 'follow' : 'unfollow';
20 | dispatch({
21 | type: `userStar/${type}`,
22 | payload: {
23 | id,
24 | },
25 | }).then((res) => {
26 | setLoading(false);
27 | setStar(!star);
28 | if (!res.result && res.message) message.error(res.message);
29 | });
30 | };
31 |
32 | return (
33 |
41 | );
42 | };
43 |
--------------------------------------------------------------------------------
/src/pages/Tag/detail/components/RelatedArticle/index.less:
--------------------------------------------------------------------------------
1 | .hot-item {
2 | display: flex;
3 | align-items: center;
4 |
5 | .avatar {
6 | margin-right: 12px;
7 | }
8 |
9 | .info {
10 | .title {
11 | font-size: 16px;
12 | line-height: 22px;
13 | color: #000;
14 | font-weight: 400;
15 | white-space: nowrap;
16 | overflow: hidden;
17 | text-overflow: ellipsis;
18 | margin: 0;
19 |
20 | a {
21 | color: #262626;
22 | }
23 | }
24 |
25 | .data {
26 | > span {
27 | color: #999;
28 | }
29 |
30 | > span:before {
31 | content: '';
32 | position: relative;
33 | top: -1px;
34 | display: inline-block;
35 | vertical-align: middle;
36 | overflow: hidden;
37 | margin: 0 8px;
38 | width: 2px;
39 | height: 2px;
40 | border-radius: 50%;
41 | background: #999;
42 | }
43 |
44 | > span:first-child:before {
45 | display: none;
46 | }
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/pages/Tag/detail/components/RelatedColumn/index.less:
--------------------------------------------------------------------------------
1 | .hot-item {
2 | display: flex;
3 | align-items: center;
4 |
5 | .avatar {
6 | margin-right: 12px;
7 | }
8 |
9 | .info {
10 | .title {
11 | font-size: 16px;
12 | line-height: 22px;
13 | color: #000;
14 | font-weight: 400;
15 | white-space: nowrap;
16 | overflow: hidden;
17 | text-overflow: ellipsis;
18 | margin: 0;
19 |
20 | a {
21 | color: #262626;
22 | }
23 | }
24 |
25 | .data {
26 | > span {
27 | color: #999;
28 | }
29 |
30 | > span:before {
31 | content: '';
32 | position: relative;
33 | top: -1px;
34 | display: inline-block;
35 | vertical-align: middle;
36 | overflow: hidden;
37 | margin: 0 8px;
38 | width: 2px;
39 | height: 2px;
40 | border-radius: 50%;
41 | background: #999;
42 | }
43 |
44 | > span:first-child:before {
45 | display: none;
46 | }
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/pages/tag/detail/components/RelatedArticle/index.less:
--------------------------------------------------------------------------------
1 | .hot-item {
2 | display: flex;
3 | align-items: center;
4 |
5 | .avatar {
6 | margin-right: 12px;
7 | }
8 |
9 | .info {
10 | .title {
11 | font-size: 16px;
12 | line-height: 22px;
13 | color: #000;
14 | font-weight: 400;
15 | white-space: nowrap;
16 | overflow: hidden;
17 | text-overflow: ellipsis;
18 | margin: 0;
19 |
20 | a {
21 | color: #262626;
22 | }
23 | }
24 |
25 | .data {
26 | > span {
27 | color: #999;
28 | }
29 |
30 | > span:before {
31 | content: '';
32 | position: relative;
33 | top: -1px;
34 | display: inline-block;
35 | vertical-align: middle;
36 | overflow: hidden;
37 | margin: 0 8px;
38 | width: 2px;
39 | height: 2px;
40 | border-radius: 50%;
41 | background: #999;
42 | }
43 |
44 | > span:first-child:before {
45 | display: none;
46 | }
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/pages/tag/detail/components/RelatedColumn/index.less:
--------------------------------------------------------------------------------
1 | .hot-item {
2 | display: flex;
3 | align-items: center;
4 |
5 | .avatar {
6 | margin-right: 12px;
7 | }
8 |
9 | .info {
10 | .title {
11 | font-size: 16px;
12 | line-height: 22px;
13 | color: #000;
14 | font-weight: 400;
15 | white-space: nowrap;
16 | overflow: hidden;
17 | text-overflow: ellipsis;
18 | margin: 0;
19 |
20 | a {
21 | color: #262626;
22 | }
23 | }
24 |
25 | .data {
26 | > span {
27 | color: #999;
28 | }
29 |
30 | > span:before {
31 | content: '';
32 | position: relative;
33 | top: -1px;
34 | display: inline-block;
35 | vertical-align: middle;
36 | overflow: hidden;
37 | margin: 0 8px;
38 | width: 2px;
39 | height: 2px;
40 | border-radius: 50%;
41 | background: #999;
42 | }
43 |
44 | > span:first-child:before {
45 | display: none;
46 | }
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/components/Content/Question/Action/Delete.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { DeleteButton } from '@/components/Button';
3 | import { Modal } from 'antd';
4 | import { useDispatch } from 'umi';
5 | import { ExclamationCircleOutlined } from '@ant-design/icons';
6 |
7 | export default ({ id, title, callback, ...props }) => {
8 | const dispatch = useDispatch();
9 |
10 | const onDelete = () => {
11 | Modal.confirm({
12 | title: `确定删除 ${title || ''}?`,
13 | okText: '确定',
14 | cancelText: '取消',
15 | centered: true,
16 | icon: ,
17 | onOk() {
18 | return new Promise(resolve => {
19 | dispatch({
20 | type: 'question/delete',
21 | payload: {
22 | id,
23 | },
24 | }).then(() => {
25 | resolve();
26 | if (callback) callback();
27 | });
28 | });
29 | },
30 | onCancel() {},
31 | });
32 | };
33 |
34 | return (
35 |
36 | 删除
37 |
38 | );
39 | };
40 |
--------------------------------------------------------------------------------
/src/components/Button/ReportButton/index.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import BaseButton from '../BaseButton';
3 | import Modal from './Modal';
4 | import { useSelector } from 'umi';
5 | import { message } from 'antd';
6 | import { FlagOutlined } from '@ant-design/icons';
7 |
8 | function ReportButton({ id, type, children, size }) {
9 | const [visible, setVisible] = useState(false);
10 |
11 | const me = useSelector((state) => state.user.me);
12 |
13 | const onClick = () => {
14 | if (!me) {
15 | message.error('请登陆');
16 | return;
17 | }
18 | setVisible(true);
19 | };
20 |
21 | const getContent = () => {
22 | if (children) return children;
23 | return '举报';
24 | };
25 |
26 | return (
27 |
28 | } size={size}>
29 | {getContent()}
30 |
31 | {
32 | setVisible(visible)}
37 | />
38 | }
39 |
40 | );
41 | }
42 | export default ReportButton;
43 |
--------------------------------------------------------------------------------
/src/pages/path/models/user/model.js:
--------------------------------------------------------------------------------
1 | import { list } from '../../services/user/service'
2 | export default {
3 | namespace: 'userActivity',
4 |
5 | state: {
6 | list:null
7 | },
8 |
9 | effects: {
10 | *list({ payload : { append , ...payload } }, { call,put }){
11 | const response = yield call(list,payload)
12 | yield put({
13 | type:'setList',
14 | payload:{append , ...(response ? response.data : {}) }
15 | })
16 | return response
17 | }
18 | },
19 |
20 | reducers:{
21 | setList(state,{ payload : { append , end , total , data , ...payload} }){
22 | const list = state.list
23 | if(!list || !append){
24 | return {
25 | ...state,
26 | list:{end , total , data , ...payload}
27 | }
28 | }
29 | const dataList = list.data.concat()
30 | data.forEach(item => {
31 | if(!dataList.find(child => child.id === item.id)){
32 | dataList.push(item)
33 | }
34 | })
35 | return {
36 | ...state,
37 | list:{...list,end,total,data:dataList}
38 | }
39 | },
40 | }
41 | }
--------------------------------------------------------------------------------
/src/components/Editor/utils.js:
--------------------------------------------------------------------------------
1 | import underscore from 'underscore.string';
2 |
3 | export const isITELLYOU = content => {
4 | return content.startsWith('');
5 | };
6 |
7 | export const isBlank = content => {
8 | if (!content) return true;
9 | return (
10 | '' ===
11 | content.replace(/<(?:br|cursor|meta) [^>]*\/>/g, '').replace(/<\/p>/g, '')
12 | );
13 | };
14 |
15 | export const extractSummary = content => {
16 | return underscore(content)
17 | .stripTags()
18 | .trim(' \n')
19 | .replace(/\n/g, ' ')
20 | .unescapeHTML()
21 | .truncate(147, '...')
22 | .value();
23 | };
24 |
25 | export const extractFirstImage = content => {
26 | if (content) {
27 | const reg = /
]{1,2000}src="([^"]{10,190})"/i;
28 | const values = reg.exec(content);
29 | return values ? values[1] : undefined;
30 | }
31 | };
32 |
33 | export const isContentSame = (prev, next) => {
34 | return prev === next || getPureContent(prev) === getPureContent(next);
35 | };
36 |
37 | export const getPureContent = content => {
38 | content = content || '';
39 | return content
40 | .replace(//gi, '')
41 | .replace(//gi, '')
42 | .replace(//gi, '');
43 | };
44 |
--------------------------------------------------------------------------------
/src/models/user/third-account.js:
--------------------------------------------------------------------------------
1 | import { find, del } from '@/services/user/third-account';
2 | export default {
3 | namespace: 'thirdAccount',
4 |
5 | state: {},
6 | effects: {
7 | *find({ payload }, { call, put }) {
8 | const response = yield call(find, payload);
9 | const { result, data } = response || {};
10 | if (result) {
11 | yield put({
12 | type: 'setDetail',
13 | payload: data,
14 | });
15 | }
16 | return response;
17 | },
18 | *delete({ payload }, { call, put }) {
19 | const response = yield call(del, payload);
20 | if (response && response.result) {
21 | yield put({
22 | type: 'updateDelete',
23 | payload: payload.type,
24 | });
25 | }
26 | return response;
27 | },
28 | },
29 | reducers: {
30 | setDetail(state, { payload }) {
31 | return {
32 | ...state,
33 | ...payload,
34 | };
35 | },
36 | updateDelete(state, { payload }) {
37 | delete state[payload];
38 | return {
39 | ...state,
40 | };
41 | },
42 | },
43 | };
44 |
--------------------------------------------------------------------------------
/src/services/doc/index.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request';
2 |
3 | export async function create({ type, ...params }) {
4 | return request(`/api/${type}/create`, {
5 | method: 'POST',
6 | data: params,
7 | });
8 | }
9 |
10 | export async function find({ id, type, ...params }) {
11 | return request(`/api/${type}/${id}/edit`, {
12 | params,
13 | });
14 | }
15 |
16 | export async function update({ id, type, ...params }) {
17 | return request(`/api/${type}/${id}/content`, {
18 | method: 'PUT',
19 | data: params,
20 | });
21 | }
22 |
23 | export async function meta({ id, type, ...params }) {
24 | return request(`/api/${type}/${id}/meta`, {
25 | method: 'PUT',
26 | data: params,
27 | });
28 | }
29 |
30 | export async function revert({ id, type, ...params }) {
31 | return request(`/api/${type}/${id}/rollback`, {
32 | method: 'PUT',
33 | data: params,
34 | });
35 | }
36 |
37 | export async function publish({ id, type, ...params }) {
38 | return request(`/api/${type}/${id}/publish`, {
39 | method: 'PUT',
40 | data: params,
41 | });
42 | }
43 |
44 | export async function paidread({ id, type, ...params }) {
45 | return request(`/api/${type}/${id}/paidread`, {
46 | method: 'PUT',
47 | data: params,
48 | });
49 | }
50 |
--------------------------------------------------------------------------------