diff --git a/packages/app/package.json b/packages/app/package.json
index cd70268a91..54c107241f 100644
--- a/packages/app/package.json
+++ b/packages/app/package.json
@@ -32,6 +32,7 @@
"@nocobase/plugin-collections": "^0.3.0-alpha.0",
"@nocobase/plugin-pages": "^0.3.0-alpha.0",
"@nocobase/server": "^0.3.0-alpha.0",
+ "@types/react-big-calendar": "^0.24.8",
"@umijs/preset-react": "1.x",
"@umijs/test": "^3.2.23",
"ahooks": "^2.9.3",
@@ -41,6 +42,7 @@
"nodemon": "^2.0.6",
"prettier": "^1.19.1",
"react": "16.14.0",
+ "react-big-calendar": "^0.30.0",
"react-dom": "16.14.0",
"react-sortable-hoc": "^1.11.0",
"styled-components": "^5.2.1",
diff --git a/packages/app/src/api/index.ts b/packages/app/src/api/index.ts
index 697e2e435c..967bafb6f3 100644
--- a/packages/app/src/api/index.ts
+++ b/packages/app/src/api/index.ts
@@ -86,7 +86,7 @@ api.resourcer.use(async (ctx: actions.Context, next) => {
if (appends.length) {
ctx.action.setParam('fields.appends', appends);
}
- console.log('ctx.action.params.fields', ctx.action.params.fields, except, appends);
+ // console.log('ctx.action.params.fields', ctx.action.params.fields, except, appends);
}
await next();
});
diff --git a/packages/app/src/api/migrations/add-fields-to-views.ts b/packages/app/src/api/migrations/add-fields-to-views.ts
new file mode 100644
index 0000000000..e176a100c5
--- /dev/null
+++ b/packages/app/src/api/migrations/add-fields-to-views.ts
@@ -0,0 +1,19 @@
+import api from '../app';
+import Database from '@nocobase/database';
+
+(async () => {
+ await api.loadPlugins();
+ const database: Database = api.database;
+ await api.database.sync({
+ tables: ['views'],
+ });
+ const [Collection, Page, User] = database.getModels(['collections', 'pages', 'users']);
+ const table = database.getTable('views');
+ const collection = await Collection.findByName('views');
+ console.log(table.getOptions().fields);
+ await collection.updateAssociations({
+ fields: table.getOptions().fields,
+ }, {
+ migrate: false,
+ });
+})();
diff --git a/packages/app/src/components/form.fields/remote-select/index.tsx b/packages/app/src/components/form.fields/remote-select/index.tsx
index 103aefb8fc..18d84f0e8a 100644
--- a/packages/app/src/components/form.fields/remote-select/index.tsx
+++ b/packages/app/src/components/form.fields/remote-select/index.tsx
@@ -14,7 +14,7 @@ import api from '@/api-client';
import { Spin } from '@nocobase/client'
function RemoteSelectComponent(props) {
- const { value, onChange, disabled, resourceName, associatedKey, filter, labelField, valueField = 'id', objectValue } = props;
+ const { value, onChange, disabled, resourceName, associatedKey, filter, labelField, valueField = 'id', objectValue, placeholder } = props;
const { data = [], loading = true } = useRequest(() => {
return api.resource(resourceName).list({
associatedKey,
@@ -26,6 +26,7 @@ function RemoteSelectComponent(props) {
return (
<>
: undefined}
allowClear
diff --git a/packages/app/src/components/views/Calendar/index.tsx b/packages/app/src/components/views/Calendar/index.tsx
new file mode 100644
index 0000000000..43e0fbf52c
--- /dev/null
+++ b/packages/app/src/components/views/Calendar/index.tsx
@@ -0,0 +1,230 @@
+import React, { useEffect, useRef, useState } from 'react';
+import { Table as AntdTable, Card, Pagination } from 'antd';
+import { Actions } from '@/components/actions';
+import ViewFactory from '@/components/views';
+import { useRequest } from 'umi';
+import api from '@/api-client';
+import { components, fields2columns } from '../SortableTable';
+import { LoadingOutlined, LeftOutlined, RightOutlined } from '@ant-design/icons';
+import './style.less';
+import { Calendar as BigCalendar, momentLocalizer } from 'react-big-calendar'
+import * as dates from 'react-big-calendar/lib/utils/dates';
+import moment from 'moment';
+const localizer = momentLocalizer(moment) // or globalizeLocalizer
+
+export const icon = ;
+
+export interface CalendarProps {
+ schema?: any;
+ activeTab?: any;
+ resourceName: string;
+ associatedName?: string;
+ associatedKey?: string;
+ [key: string]: any;
+}
+
+// let weekRangeFormat = ({ start, end }, culture, local) =>
+// local.format(start, 'MMMM DD', culture) +
+// ' – ' +
+// local.format(end, dates.eq(start, end, 'month') ? 'DD' : 'MMMM DD', culture)
+
+function toEvents(data, options: any = {}) {
+ const { startDateField, endDateField, labelField, idField = 'id' } = options;
+ if (!Array.isArray(data)) {
+ return [];
+ }
+ return data.map(item => ({
+ id: item[idField],
+ title: item[labelField],
+ allDay: true,
+ start: moment(item[startDateField||'createdAt'] || item.created_at).toDate(),
+ end: moment(item[endDateField || startDateField || 'createdAt'] || item.created_at).toDate(),
+ }));
+}
+
+export function Calendar(props: CalendarProps) {
+ console.log(props);
+ const {
+ activeTab = {},
+ pageInfo = {},
+ schema,
+ resourceName,
+ associatedName,
+ associatedKey,
+ isFieldComponent,
+ onSelected,
+ multiple = true,
+ selectedRowKeys: srk,
+ } = props;
+ const { rowKey = 'id', labelField, startDateField, endDateField, name: viewName, actionDefaultParams = {}, fields = [], rowViewName, actions = [], paginated = true, defaultPerPage = 10 } = schema;
+ const { filter: defaultFilter = {} } = actionDefaultParams;
+ const { sourceKey = 'id' } = activeTab.field||{};
+ const drawerRef = useRef();
+ const [filterCount, setFilterCount] = useState(0);
+ const name = associatedName ? `${associatedName}.${resourceName}` : resourceName;
+ const { data, loading, pagination, mutate, refresh, params, run } = useRequest((params = {}) => {
+ const { current, pageSize, sorter, filter, ...restParams } = params;
+ return api.resource(name).list({
+ associatedKey,
+ // page: paginated ? current : 1,
+ perPage: -1,
+ sorter,
+ // filter,
+ viewName,
+ ...actionDefaultParams,
+ filter: {
+ and: [
+ defaultFilter,
+ filter,
+ ].filter(obj => obj && Object.keys(obj).length)
+ }
+ })
+ .then(({data = [], meta = {}}) => {
+ return {
+ data: {
+ list: data,
+ total: meta.count||data.length,
+ },
+ };
+ });
+ }, {
+ paginated,
+ defaultPageSize: defaultPerPage,
+ });
+ console.log(schema, data);
+ const [selectedRowKeys, setSelectedRowKeys] = useState(srk||[]);
+ const onChange = (selectedRowKeys: React.ReactText[], selectedRows: React.ReactText[]) => {
+ setSelectedRowKeys(selectedRowKeys);
+ onSelected && onSelected(selectedRows);
+ }
+ const [formMode, setFormMode] = useState('update');
+ const [calendarView, setCalendarView] = useState('month');
+ useEffect(() => {
+ setSelectedRowKeys(srk);
+ }, [srk]);
+ const tableProps: any = {};
+ if (actions.length) {
+ tableProps.rowSelection = {
+ type: multiple ? 'checkbox' : 'radio',
+ selectedRowKeys,
+ onChange,
+ }
+ }
+
+ const events = toEvents(data?.list, {
+ idField: rowKey,
+ labelField,
+ startDateField,
+ endDateField,
+ });
+
+ const messages = {
+ allDay: '',
+ previous:
,
+ next:
,
+ today: '今天',
+ month: '月',
+ week: '周',
+ day: '天',
+ agenda: '列表',
+ date: '日期',
+ time: '时间',
+ event: '事件',
+ noEventsInRange: '无',
+ showMore: (count) => `还有 ${count} 项`
+ }
+
+ console.log('events', data)
+ return (
+
+ {/* {
+ refresh();
+ }}
+ onTrigger={{
+ async filter(values) {
+ console.log('filter', values);
+ const items = values.filter.and || values.filter.or;
+ setFilterCount(Object.keys(items).length);
+ // @ts-ignore
+ run({...params[0], filter: values.filter});
+ },
+ async destroy() {
+ await api.resource(name).destroy({
+ associatedKey,
+ filter: {
+ [`${rowKey}.in`]: selectedRowKeys,
+ },
+ });
+ await refresh();
+ // @ts-ignore
+ window.routesReload && window.routesReload();
+ console.log('destroy.onTrigger', selectedRowKeys);
+ },
+ }}
+ /> */}
+ {
+ refresh();
+ }}
+ />
+ {
+ if (dates.eq(start, end, 'month')) {
+ return local.format(start, 'Y年M月', culture);
+ }
+ return `${local.format(start, 'Y年M月', culture)} - ${local.format(end, 'Y年M月', culture)}`;
+ }
+ }}
+ events={events}
+ onSelectSlot={(slotInfo) => {
+ // setFormMode('create');
+ // drawerRef.current.setVisible(true);
+ // console.log('onSelectSlot', slotInfo)
+ }}
+ onView={(view) => {
+ setCalendarView(view);
+ console.log(view)
+ }}
+ onSelectEvent={(event) => {
+ console.log(event);
+ if (isFieldComponent) {
+ return;
+ }
+ setFormMode('update');
+ drawerRef.current.setVisible(true);
+ drawerRef.current.getData(event[rowKey]);
+ // drawerRef.current.
+ }}
+ onRangeChange={(range) => {
+ console.log({range})
+ }}
+ views={['month', 'week', 'day']}
+ // step={120}
+ // showMultiDayTimes
+ // max={dates.add(dates.endOf(new Date(2015, 17, 1), 'day'), -1, 'hours')}
+ // defaultDate={new Date(2015, 3, 1)}
+ components={{
+ timeGutterHeader: () => 全天
,
+ }}
+ localizer={localizer}
+ />
+
+ );
+}
diff --git a/packages/app/src/components/views/Calendar/style.less b/packages/app/src/components/views/Calendar/style.less
new file mode 100644
index 0000000000..d9ade51126
--- /dev/null
+++ b/packages/app/src/components/views/Calendar/style.less
@@ -0,0 +1,634 @@
+@charset "UTF-8";
+.rbc-btn {
+ color: inherit;
+ font: inherit;
+ margin: 0; }
+
+button.rbc-btn {
+ overflow: visible;
+ text-transform: none;
+ -webkit-appearance: button;
+ cursor: pointer; }
+
+button[disabled].rbc-btn {
+ cursor: not-allowed; }
+
+button.rbc-input::-moz-focus-inner {
+ border: 0;
+ padding: 0; }
+
+.rbc-calendar {
+ box-sizing: border-box;
+ // height: 75vh;
+ display: flex;
+ flex-direction: column;
+ align-items: stretch; }
+
+.rbc-calendar *,
+.rbc-calendar *:before,
+.rbc-calendar *:after {
+ box-sizing: inherit; }
+
+.rbc-abs-full, .rbc-row-bg {
+ overflow: hidden;
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0; }
+
+.rbc-ellipsis, .rbc-event-label, .rbc-row-segment .rbc-event-content, .rbc-show-more {
+ display: block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap; }
+
+.rbc-rtl {
+ direction: rtl; }
+
+.rbc-off-range {
+ color: rgba(0,0,0,.25); }
+
+.rbc-off-range-bg {
+ // background: #e6e6e6;
+}
+
+.rbc-header {
+ // font-size: 16px;
+ overflow: hidden;
+ flex: 1 0 0%;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ padding: 4px 12px;
+ text-align: right;
+ vertical-align: middle;
+ // font-weight: 500;
+ min-height: 32px;
+ color: rgba(0,0,0,.85);
+ margin: 0 4px;
+ border-bottom: 2px solid #f0f0f0;
+}
+ .rbc-header + .rbc-header {
+ // border-left: 1px solid #f0f0f0;
+ }
+ .rbc-rtl .rbc-header + .rbc-header {
+ border-left-width: 0;
+ border-right: 1px solid #f0f0f0; }
+ .rbc-header > a, .rbc-header > a:active, .rbc-header > a:visited {
+ color: inherit;
+ text-decoration: none; }
+
+.rbc-row-content {
+ position: relative;
+ user-select: none;
+ -webkit-user-select: none;
+ z-index: 4; }
+
+.rbc-row-content-scrollable {
+ display: flex;
+ flex-direction: column;
+ height: 100%; }
+ .rbc-row-content-scrollable .rbc-row-content-scroll-container {
+ height: 100%;
+ overflow-y: scroll;
+ /* Hide scrollbar for Chrome, Safari and Opera */
+ -ms-overflow-style: none;
+ /* IE and Edge */
+ scrollbar-width: none;
+ /* Firefox */ }
+ .rbc-row-content-scrollable .rbc-row-content-scroll-container::-webkit-scrollbar {
+ display: none; }
+
+
+.rbc-toolbar {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+ align-items: center;
+ margin-bottom: 10px;
+ font-size: 16px; }
+ .rbc-toolbar .rbc-toolbar-label {
+ flex-grow: 1;
+ padding: 0 10px;
+ text-align: center; }
+ .rbc-toolbar button {
+ outline: none;
+ font-size: 14px;
+ line-height: 1.5715;
+ height: 32px;
+ color: #373a3c;
+ display: inline-block;
+ margin: 0;
+ position: relative;
+ z-index: 1;
+ text-align: center;
+ vertical-align: middle;
+ background: none;
+ background-image: none;
+ border: 1px solid #d9d9d9;
+ padding: 4px 15px;
+ border-radius: 2px;
+ line-height: normal;
+ white-space: nowrap; }
+ .rbc-toolbar button:active, .rbc-toolbar button.rbc-active {
+ // background-image: none;
+ // box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
+ // background-color: #e6e6e6;
+ z-index: 2;
+ color: #1890ff;
+ border-color: #1890ff; }
+ .rbc-toolbar button:active:hover, .rbc-toolbar button:active:focus, .rbc-toolbar button.rbc-active:hover, .rbc-toolbar button.rbc-active:focus {
+ // color: #373a3c;
+ // background-color: #d4d4d4;
+ // border-color: #8c8c8c;
+ z-index: 2;
+ color: #40a9ff;
+ border-color: #40a9ff;
+ }
+ // .rbc-toolbar button:focus {
+ // color: #373a3c;
+ // background-color: #e6e6e6;
+ // border-color: #adadad; }
+ .rbc-toolbar button:hover {
+ // color: #373a3c;
+ // background-color: #e6e6e6;
+ z-index: 2;
+ color: #40a9ff;
+ border-color: #40a9ff;
+ }
+
+.rbc-btn-group {
+ display: inline-block;
+ white-space: nowrap; }
+ .rbc-btn-group > button:first-child:not(:last-child) {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0; }
+ .rbc-btn-group > button:last-child:not(:first-child) {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0; }
+ .rbc-rtl .rbc-btn-group > button:first-child:not(:last-child) {
+ border-radius: 4px;
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0; }
+ .rbc-rtl .rbc-btn-group > button:last-child:not(:first-child) {
+ border-radius: 4px;
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0; }
+ .rbc-btn-group > button:not(:first-child):not(:last-child) {
+ border-radius: 0; }
+ .rbc-btn-group button + button {
+ margin-left: -1px; }
+ .rbc-rtl .rbc-btn-group button + button {
+ margin-left: 0;
+ margin-right: -1px; }
+ .rbc-btn-group + .rbc-btn-group,
+ .rbc-btn-group + button {
+ margin-left: 10px; }
+
+.rbc-event {
+ border: none;
+ box-sizing: border-box;
+ box-shadow: none;
+ margin: 0;
+ padding: 2px 5px;
+ background-color: #f0f0f0;
+ border-radius: 2px;
+ // color: #1890ff;
+ cursor: pointer;
+ font-size: 12px;
+ width: 100%;
+ text-align: left;
+ &:hover {
+ background-color: #e6f7ff;
+ color: #1890ff;
+ }
+}
+ .rbc-slot-selecting .rbc-event {
+ cursor: inherit;
+ pointer-events: none; }
+ .rbc-event.rbc-selected {
+ background-color: #e6f7ff;
+ color: #1890ff;
+ }
+ .rbc-event:focus {
+ // outline: 5px auto #3b99fc;
+ }
+
+.rbc-event-label {
+ font-size: 80%; }
+
+.rbc-event-overlaps {
+ box-shadow: -1px 1px 5px 0px rgba(51, 51, 51, 0.5); }
+
+.rbc-event-continues-prior {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0; }
+
+.rbc-event-continues-after {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0; }
+
+.rbc-event-continues-earlier {
+ border-top-left-radius: 0;
+ border-top-right-radius: 0; }
+
+.rbc-event-continues-later {
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0; }
+
+.rbc-row {
+ display: flex;
+ flex-direction: row; }
+
+.rbc-row-segment {
+ padding: 0 4px 1px 4px; }
+
+.rbc-selected-cell {
+ background-color: rgba(0, 0, 0, 0.1); }
+
+.rbc-show-more {
+ z-index: 4;
+ font-weight: bold;
+ font-size: 85%;
+ height: auto;
+ line-height: normal;
+ color: inherit;
+ padding: 2px 5px;
+}
+
+.rbc-month-view {
+ position: relative;
+ // border: 1px solid #f0f0f0;
+ display: flex;
+ flex-direction: column;
+ flex: 1 0 0;
+ width: 100%;
+ user-select: none;
+ -webkit-user-select: none;
+ height: 68vh; }
+
+.rbc-month-header {
+ display: flex;
+ flex-direction: row; }
+
+.rbc-month-row {
+ display: flex;
+ position: relative;
+ flex-direction: column;
+ flex: 1 0 0;
+ flex-basis: 0px;
+ overflow: hidden;
+ height: 100%; }
+ .rbc-month-row + .rbc-month-row {
+ // border-top: 1px solid #f0f0f0;
+ }
+
+.rbc-date-cell {
+ // cursor: pointer;
+ flex: 1 1 0;
+ min-width: 0;
+ padding-right: 12px;
+ padding-top: 4px;
+ text-align: right; }
+ .rbc-date-cell.rbc-now a {
+ // font-weight: bold;
+ color: #1890ff;
+ }
+ .rbc-date-cell > a, .rbc-date-cell > a:active, .rbc-date-cell > a:visited {
+ color: inherit;
+ text-decoration: none;
+ }
+ .rbc-date-cell > a:hover {
+ color: #1890ff;
+ }
+
+.rbc-row-bg {
+ display: flex;
+ flex-direction: row;
+ flex: 1 0 0;
+ overflow: hidden; }
+
+
+
+.rbc-day-bg {
+ flex: 1 0 0%;
+ // border-top: 2px solid #f0f0f0;
+ margin: 0 4px;
+ &:hover {
+ background: #f5f5f5;
+ }
+ // cursor: pointer;
+}
+
+.rbc-month-view {
+ .rbc-day-bg {
+ border-top: 2px solid #f0f0f0;
+ }
+ .rbc-today {
+ border-color: #1890ff !important;
+ background-color: #e6f7ff !important;
+ }
+ .rbc-header {
+ border-bottom: 0 !important;
+ }
+}
+
+ .rbc-day-bg + .rbc-day-bg {
+ // margin-left: 8px;
+ // border-left: 1px solid #f0f0f0;
+ }
+ .rbc-rtl .rbc-day-bg + .rbc-day-bg {
+ // border-left-width: 0;
+ // border-right: 1px solid #f0f0f0;
+ }
+
+.rbc-overlay {
+ position: absolute;
+ z-index: 5;
+ margin-top: 5px;
+ border-radius: 2px;
+ // border: 1px solid #e5e5e5;
+ background-color: #fff;
+ box-shadow: 0 3px 6px -4px rgba(0,0,0,.12), 0 6px 16px 0 rgba(0,0,0,.08), 0 9px 28px 8px rgba(0,0,0,.05);
+ padding: 12px 16px; }
+ .rbc-overlay > * + * {
+ margin-top: 1px; }
+
+.rbc-overlay-header {
+ font-weight: 500;
+ min-height: 32px;
+ border-bottom: 1px solid #f0f0f0;
+ margin: -12px -16px 12px -16px;
+ padding: 5px 16px 4px; }
+
+.rbc-agenda-view {
+ display: flex;
+ flex-direction: column;
+ flex: 1 0 0;
+ overflow: auto; }
+ .rbc-agenda-view table.rbc-agenda-table {
+ width: 100%;
+ border: 1px solid #f0f0f0;
+ border-spacing: 0;
+ border-collapse: collapse; }
+ .rbc-agenda-view table.rbc-agenda-table tbody > tr > td {
+ padding: 5px 10px;
+ vertical-align: top; }
+ .rbc-agenda-view table.rbc-agenda-table .rbc-agenda-time-cell {
+ padding-left: 15px;
+ padding-right: 15px;
+ text-transform: lowercase; }
+ .rbc-agenda-view table.rbc-agenda-table tbody > tr > td + td {
+ border-left: 1px solid #f0f0f0; }
+ .rbc-rtl .rbc-agenda-view table.rbc-agenda-table tbody > tr > td + td {
+ border-left-width: 0;
+ border-right: 1px solid #f0f0f0; }
+ .rbc-agenda-view table.rbc-agenda-table tbody > tr + tr {
+ border-top: 1px solid #f0f0f0; }
+ .rbc-agenda-view table.rbc-agenda-table thead > tr > th {
+ padding: 3px 5px;
+ text-align: left;
+ border-bottom: 1px solid #f0f0f0; }
+ .rbc-rtl .rbc-agenda-view table.rbc-agenda-table thead > tr > th {
+ text-align: right; }
+
+.rbc-agenda-time-cell {
+ text-transform: lowercase; }
+ .rbc-agenda-time-cell .rbc-continues-after:after {
+ content: ' »'; }
+ .rbc-agenda-time-cell .rbc-continues-prior:before {
+ content: '« '; }
+
+.rbc-agenda-date-cell,
+.rbc-agenda-time-cell {
+ white-space: nowrap; }
+
+.rbc-agenda-event-cell {
+ width: 100%; }
+
+.rbc-time-column {
+ display: flex;
+ flex-direction: column;
+ min-height: 100%; }
+ .rbc-time-column .rbc-timeslot-group {
+ flex: 1; }
+
+.rbc-timeslot-group {
+ border-bottom: 1px solid #f0f0f0;
+ min-height: 40px;
+ line-height: 39px;
+ display: flex;
+ flex-flow: column nowrap;
+ // cursor: pointer;
+ &:hover {
+ background: #f0f0f0;
+ }
+}
+
+.rbc-time-gutter,
+.rbc-header-gutter {
+ flex: none; }
+
+.rbc-label {
+ padding: 0 5px; }
+
+.rbc-day-slot {
+ position: relative; }
+ .rbc-day-slot .rbc-events-container {
+ bottom: 0;
+ left: 0;
+ position: absolute;
+ right: 0;
+ margin-right: 10px;
+ top: 0; }
+ .rbc-day-slot .rbc-events-container.rbc-rtl {
+ left: 10px;
+ right: 0; }
+ .rbc-day-slot .rbc-event {
+ border: 1px solid #265985;
+ display: flex;
+ max-height: 100%;
+ min-height: 20px;
+ flex-flow: column wrap;
+ align-items: flex-start;
+ overflow: hidden;
+ position: absolute; }
+ .rbc-day-slot .rbc-event-label {
+ flex: none;
+ padding-right: 5px;
+ width: auto; }
+ .rbc-day-slot .rbc-event-content {
+ width: 100%;
+ flex: 1 1 0;
+ word-wrap: break-word;
+ line-height: 1;
+ height: 100%;
+ min-height: 1em; }
+ .rbc-day-slot .rbc-time-slot {
+ // border-top: 1px solid #f7f7f7;
+ }
+.rbc-time-header-gutter {
+ line-height: 40px;
+}
+.rbc-time-header-cell {
+ min-height: 32px !important;
+}
+.rbc-calendar.view-week {
+ .rbc-time-header-cell {
+ margin-top: -32px;
+ margin-bottom: 4px;
+ }
+ .rbc-time-view {
+ padding-top: 32px;
+ border-top: 0;
+ }
+ .rbc-header {
+ padding: 4px 8px;
+ }
+ .rbc-time-header-content {
+ padding: 4px 0;
+ }
+ .rbc-time-header-gutter {
+ padding: 0;
+ padding-top: 2px;
+ > div {
+ border-top: 2px solid #f0f0f0;
+ padding: 0 5px;
+ }
+ }
+}
+.rbc-time-view-resources .rbc-time-gutter,
+.rbc-time-view-resources .rbc-time-header-gutter {
+ position: sticky;
+ left: 0;
+ background-color: white;
+ border-right: 1px solid #f0f0f0;
+ z-index: 10;
+ margin-right: -1px; }
+
+.rbc-time-view-resources .rbc-time-header {
+ overflow: hidden; }
+
+.rbc-time-view-resources .rbc-time-header-content {
+ min-width: auto;
+ flex: 1 0 0;
+ flex-basis: 0px; }
+
+.rbc-time-view-resources .rbc-time-header-cell-single-day {
+ display: none; }
+
+.rbc-time-view-resources .rbc-day-slot {
+ min-width: 140px; }
+
+.rbc-time-view-resources .rbc-header,
+.rbc-time-view-resources .rbc-day-bg {
+ width: 140px;
+ flex: 1 1 0;
+ flex-basis: 0 px; }
+
+.rbc-time-header-content + .rbc-time-header-content {
+ margin-left: -1px; }
+
+.rbc-time-slot {
+ flex: 1 0 0; }
+ .rbc-time-slot.rbc-now {
+ font-weight: bold; }
+
+.rbc-day-header {
+ text-align: center; }
+
+.rbc-slot-selection {
+ z-index: 10;
+ position: absolute;
+ background-color: rgba(0, 0, 0, 0.5);
+ color: white;
+ font-size: 75%;
+ width: 100%;
+ padding: 3px; }
+
+.rbc-slot-selecting {
+ cursor: move; }
+
+.rbc-time-view {
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+ width: 100%;
+ border-top: 1px solid #f0f0f0;
+ min-height: 0; }
+ .rbc-time-view .rbc-time-gutter {
+ white-space: nowrap; }
+ .rbc-time-view .rbc-allday-cell {
+ box-sizing: content-box;
+ width: 100%;
+ height: 100%;
+ position: relative; }
+ .rbc-time-view .rbc-allday-cell + .rbc-allday-cell {
+ border-left: 1px solid #f0f0f0; }
+ .rbc-time-view .rbc-allday-events {
+ position: relative;
+ z-index: 4; }
+ .rbc-time-view .rbc-row {
+ box-sizing: border-box;
+ min-height: 20px; }
+
+.rbc-time-header {
+ display: flex;
+ flex: 0 0 auto;
+ flex-direction: row; }
+ .rbc-time-header.rbc-overflowing {
+ border-right: 1px solid #f0f0f0; }
+ .rbc-rtl .rbc-time-header.rbc-overflowing {
+ border-right-width: 0;
+ border-left: 1px solid #f0f0f0; }
+ .rbc-time-header > .rbc-row:first-child {
+ border-bottom: 1px solid #f0f0f0; }
+ .rbc-time-header > .rbc-row.rbc-row-resource {
+ border-bottom: 1px solid #f0f0f0; }
+
+.rbc-time-header-cell-single-day {
+ display: none; }
+
+.rbc-time-header-content {
+ flex: 1;
+ display: flex;
+ min-width: 0;
+ flex-direction: column;
+ // border-left: 1px solid #f0f0f0;
+}
+ .rbc-rtl .rbc-time-header-content {
+ border-left-width: 0;
+ border-right: 1px solid #f0f0f0; }
+ .rbc-time-header-content > .rbc-row.rbc-row-resource {
+ border-bottom: 1px solid #f0f0f0;
+ flex-shrink: 0; }
+
+.rbc-time-content {
+ display: flex;
+ flex: 1 0 0%;
+ align-items: flex-start;
+ width: 100%;
+ border-top: 1px solid #f0f0f0;
+ overflow-y: auto;
+ position: relative; }
+ .rbc-time-content > .rbc-time-gutter {
+ flex: none; }
+ .rbc-time-content > * + * > * {
+ // border-left: 1px solid #f0f0f0;
+ }
+ .rbc-rtl .rbc-time-content > * + * > * {
+ border-left-width: 0;
+ border-right: 1px solid #f0f0f0; }
+ .rbc-time-content > .rbc-day-slot {
+ width: 100%;
+ user-select: none;
+ -webkit-user-select: none; }
+
+.rbc-current-time-indicator {
+ position: absolute;
+ z-index: 3;
+ left: 0;
+ right: 0;
+ height: 1px;
+ background-color: #74ad31;
+ pointer-events: none; }
diff --git a/packages/app/src/components/views/Form/DrawerForm.tsx b/packages/app/src/components/views/Form/DrawerForm.tsx
index 92f129361a..86b169f9c5 100644
--- a/packages/app/src/components/views/Form/DrawerForm.tsx
+++ b/packages/app/src/components/views/Form/DrawerForm.tsx
@@ -20,6 +20,8 @@ import { useRequest } from 'umi';
import api from '@/api-client';
import { Spin } from '@nocobase/client';
+const actions = createFormActions();
+
export const DrawerForm = forwardRef((props: any, ref) => {
console.log(props);
const {
@@ -50,7 +52,7 @@ export const DrawerForm = forwardRef((props: any, ref) => {
setVisible,
getData: run,
}));
- const actions = createFormActions();
+
console.log({onFinish});
return (
();
@@ -21,6 +22,7 @@ export function getViewTemplate(template: string) {
return TEMPLATES.get(template);
}
+registerView('Calendar', Calendar);
registerView('FilterForm', FilterForm)
registerView('DrawerForm', DrawerForm);
registerView('PermissionForm', DrawerForm);
diff --git a/packages/plugin-collections/src/collections/views.ts b/packages/plugin-collections/src/collections/views.ts
index fecde98b43..cbd177f8dd 100644
--- a/packages/plugin-collections/src/collections/views.ts
+++ b/packages/plugin-collections/src/collections/views.ts
@@ -55,9 +55,9 @@ export default {
required: true,
dataSource: [
{ label: '表格', value: 'table' },
+ { label: '日历', value: 'calendar' },
// { label: '表单', value: 'form' },
{ label: '看板', value: 'kanban', disabled: true },
- { label: '日历', value: 'calendar', disabled: true },
{ label: '地图', value: 'map', disabled: true },
],
component: {
@@ -72,9 +72,119 @@ export default {
"target": "filter",
"condition": "{{ $self.value !== 'form' }}"
},
+ {
+ type: "value:schema",
+ target: "labelField",
+ "condition": "{{ $self.value === 'calendar' }}",
+ schema: {
+ "x-component-props": {
+ associatedKey: "{{ $form.values && $form.values.associatedKey }}"
+ },
+ },
+ },
+ {
+ type: "value:schema",
+ target: "starDateField",
+ "condition": "{{ $self.value === 'calendar' }}",
+ schema: {
+ "x-component-props": {
+ associatedKey: "{{ $form.values && $form.values.associatedKey }}"
+ },
+ },
+ },
+ {
+ type: "value:schema",
+ target: "endDateField",
+ "condition": "{{ $self.value === 'calendar' }}",
+ schema: {
+ "x-component-props": {
+ associatedKey: "{{ $form.values && $form.values.associatedKey }}"
+ },
+ },
+ },
+ {
+ "type": "value:visible",
+ "target": "labelField",
+ "condition": "{{ $self.value === 'calendar' }}",
+ },
+ {
+ "type": "value:visible",
+ "target": "starDateField",
+ "condition": "{{ $self.value === 'calendar' }}",
+ },
+ {
+ "type": "value:visible",
+ "target": "endDateField",
+ "condition": "{{ $self.value === 'calendar' }}",
+ },
],
},
},
+ {
+ interface: 'select',
+ type: 'virtual',
+ title: '标题字段',
+ name: 'labelField',
+ required: true,
+ component: {
+ type: 'remoteSelect',
+ showInDetail: true,
+ showInForm: true,
+ 'x-component-props': {
+ mode: 'simple',
+ resourceName: 'collections.fields',
+ labelField: 'title',
+ valueField: 'name',
+ filter: {
+ type: 'string',
+ },
+ },
+ },
+ },
+ {
+ interface: 'select',
+ type: 'virtual',
+ title: '开始日期字段',
+ name: 'starDateField',
+ // required: true,
+ component: {
+ type: 'remoteSelect',
+ showInDetail: true,
+ showInForm: true,
+ 'x-component-props': {
+ placeholder: '默认为创建时间字段',
+ mode: 'simple',
+ resourceName: 'collections.fields',
+ labelField: 'title',
+ valueField: 'name',
+ filter: {
+ type: 'date',
+ },
+ },
+ },
+ },
+ {
+ interface: 'select',
+ type: 'virtual',
+ title: '结束日期字段',
+ name: 'endDateField',
+ // required: true,
+ component: {
+ type: 'remoteSelect',
+ showInDetail: true,
+ showInForm: true,
+ 'x-component-props': {
+ placeholder: '默认为创建时间字段',
+ mode: 'simple',
+ resourceName: 'collections.fields',
+ labelField: 'title',
+ valueField: 'name',
+ filter: {
+ type: 'date',
+ },
+ },
+ },
+ },
{
interface: 'json',
type: 'json',
@@ -98,6 +208,7 @@ export default {
// { label: '表单', value: 'DrawerForm' },
{ label: '常规表格', value: 'Table' },
{ label: '简易表格', value: 'SimpleTable' },
+ // { label: '日历模板', value: 'Calendar' },
],
component: {
type: 'string',
diff --git a/packages/plugin-collections/src/models/field.ts b/packages/plugin-collections/src/models/field.ts
index 6c9ef4f789..8ee1d59560 100644
--- a/packages/plugin-collections/src/models/field.ts
+++ b/packages/plugin-collections/src/models/field.ts
@@ -159,7 +159,7 @@ export class FieldModel extends BaseModel {
// }
}
const f = await Field.create(targetOptions, options);
- console.log({targetOptions}, f.get('options'));
+ // console.log({targetOptions}, f.get('options'));
}
setInterface(value) {