20241113-a
This commit is contained in:
5
.dockerignore
Normal file
5
.dockerignore
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
.history
|
||||||
|
node_modules
|
||||||
|
build
|
||||||
|
dist
|
||||||
|
README.md
|
||||||
36
.github/workflows/publish.yml
vendored
Normal file
36
.github/workflows/publish.yml
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*.*.*'
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- 'master'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
call_workflow_build_node:
|
||||||
|
uses: infrastructure/reusing_workflows/.github/workflows/build_node.yml@main
|
||||||
|
with:
|
||||||
|
node-version: '16.x'
|
||||||
|
dist-dir: 'dist'
|
||||||
|
artifact-name: 'artifact'
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
|
call_workflow_publish_docker:
|
||||||
|
uses: infrastructure/reusing_workflows/.github/workflows/publish_docker.yml@main
|
||||||
|
with:
|
||||||
|
artifact-name: 'artifact'
|
||||||
|
docker_context: '.'
|
||||||
|
dockerfile_path: './docker/Dockerfile'
|
||||||
|
platforms: ${{ github.event_name == 'pull_request' && 'linux/amd64' || 'linux/amd64,linux/arm64' }}
|
||||||
|
secrets: inherit
|
||||||
|
needs: call_workflow_build_node
|
||||||
|
|
||||||
|
call_workflow_deploy_compose:
|
||||||
|
uses: infrastructure/reusing_workflows/.github/workflows/deploy_compose.yml@main
|
||||||
|
with:
|
||||||
|
stack_file_name: compose.admin.yml
|
||||||
|
env_file_name: ${{ github.event_name == 'pull_request' && '.env.dev' || '.env.base' }},.env.version
|
||||||
|
args: up -d
|
||||||
|
pull_images_first: true
|
||||||
|
secrets: inherit
|
||||||
|
needs: call_workflow_publish_docker
|
||||||
37
.gitignore
vendored
Normal file
37
.gitignore
vendored
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
# dependencies
|
||||||
|
/node_modules
|
||||||
|
/.pnp
|
||||||
|
.pnp.js
|
||||||
|
|
||||||
|
# testing
|
||||||
|
/coverage
|
||||||
|
|
||||||
|
# production
|
||||||
|
/build
|
||||||
|
/dist
|
||||||
|
|
||||||
|
# misc
|
||||||
|
.DS_Store
|
||||||
|
.env.local
|
||||||
|
.env.development.local
|
||||||
|
.env.test.local
|
||||||
|
.env.production.local
|
||||||
|
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
*.code-workspace
|
||||||
|
|
||||||
|
.idea/
|
||||||
|
*.iml
|
||||||
|
|
||||||
|
# Local History for Visual Studio Code
|
||||||
|
.history/
|
||||||
|
yarn.lock
|
||||||
|
.eslintcache
|
||||||
1
.prettierignore
Normal file
1
.prettierignore
Normal file
@@ -0,0 +1 @@
|
|||||||
|
**/dist
|
||||||
6
.prettierrc.yaml
Normal file
6
.prettierrc.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
trailingComma: 'es5'
|
||||||
|
tabWidth: 2
|
||||||
|
semi: true
|
||||||
|
singleQuote: true
|
||||||
|
bracketSpacing: true
|
||||||
|
endOfLine: 'auto'
|
||||||
7
.vscode/settings.json
vendored
Normal file
7
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"typescript.tsdk": "node_modules\\typescript\\lib",
|
||||||
|
"CodeGPT.Autocomplete.suggestionDelay": 0,
|
||||||
|
"CodeGPT.Autocomplete.maxTokens": 1000,
|
||||||
|
"CodeGPT.Autocomplete.provider": "Ollama - llama3:instruct",
|
||||||
|
"CodeGPT.apiKey": "Ollama"
|
||||||
|
}
|
||||||
8
README.md
Normal file
8
README.md
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
REACT_APP_BASE=/tianmuhu PUBLIC_URL=/tianmuhu/admin npm run build
|
||||||
|
|
||||||
|
docker build -t ccr.ccs.tencentyun.com/olms/admin:1.1-subpath-changzhou -f Dockerfile.subpath --build-arg BASE_PATH=/changzhou .
|
||||||
|
|
||||||
|
系统配置
|
||||||
|
系统LOGO
|
||||||
|
微信服务
|
||||||
|
考勤客户端下载路径
|
||||||
38
babel.config.json
Normal file
38
babel.config.json
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"presets": [
|
||||||
|
[
|
||||||
|
"@babel/preset-env",
|
||||||
|
{
|
||||||
|
"targets": {
|
||||||
|
"edge": "17",
|
||||||
|
"firefox": "60",
|
||||||
|
"chrome": "67",
|
||||||
|
"safari": "11.1"
|
||||||
|
},
|
||||||
|
"useBuiltIns": "usage",
|
||||||
|
"corejs": "3.6.5"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"@babel/preset-react",
|
||||||
|
{
|
||||||
|
"runtime": "classic"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"@babel/preset-typescript",
|
||||||
|
{
|
||||||
|
"isTSX": true,
|
||||||
|
"allExtensions": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"plugins": [
|
||||||
|
[
|
||||||
|
"@babel/plugin-proposal-decorators",
|
||||||
|
{
|
||||||
|
"legacy": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
]
|
||||||
|
}
|
||||||
106
config/env.js
Normal file
106
config/env.js
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const paths = require('./paths');
|
||||||
|
|
||||||
|
// Make sure that including paths.js after env.js will read .env variables.
|
||||||
|
delete require.cache[require.resolve('./paths')];
|
||||||
|
|
||||||
|
const NODE_ENV = process.env.NODE_ENV;
|
||||||
|
if (!NODE_ENV) {
|
||||||
|
throw new Error(
|
||||||
|
'The NODE_ENV environment variable is required but was not specified.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use
|
||||||
|
const dotenvFiles = [
|
||||||
|
`${paths.dotenv}.${NODE_ENV}.local`,
|
||||||
|
// Don't include `.env.local` for `test` environment
|
||||||
|
// since normally you expect tests to produce the same
|
||||||
|
// results for everyone
|
||||||
|
NODE_ENV !== 'test' && `${paths.dotenv}.local`,
|
||||||
|
`${paths.dotenv}.${NODE_ENV}`,
|
||||||
|
paths.dotenv,
|
||||||
|
].filter(Boolean);
|
||||||
|
|
||||||
|
// Load environment variables from .env* files. Suppress warnings using silent
|
||||||
|
// if this file is missing. dotenv will never modify any environment variables
|
||||||
|
// that have already been set. Variable expansion is supported in .env files.
|
||||||
|
// https://github.com/motdotla/dotenv
|
||||||
|
// https://github.com/motdotla/dotenv-expand
|
||||||
|
dotenvFiles.forEach((dotenvFile) => {
|
||||||
|
if (fs.existsSync(dotenvFile)) {
|
||||||
|
require('dotenv-expand').expand(
|
||||||
|
require('dotenv').config({
|
||||||
|
path: dotenvFile,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// We support resolving modules according to `NODE_PATH`.
|
||||||
|
// This lets you use absolute paths in imports inside large monorepos:
|
||||||
|
// https://github.com/facebook/create-react-app/issues/253.
|
||||||
|
// It works similar to `NODE_PATH` in Node itself:
|
||||||
|
// https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders
|
||||||
|
// Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored.
|
||||||
|
// Otherwise, we risk importing Node.js core modules into an app instead of webpack shims.
|
||||||
|
// https://github.com/facebook/create-react-app/issues/1023#issuecomment-265344421
|
||||||
|
// We also resolve them to make sure all tools using them work consistently.
|
||||||
|
const appDirectory = fs.realpathSync(process.cwd());
|
||||||
|
process.env.NODE_PATH = (process.env.NODE_PATH || '')
|
||||||
|
.split(path.delimiter)
|
||||||
|
.filter((folder) => folder && !path.isAbsolute(folder))
|
||||||
|
.map((folder) => path.resolve(appDirectory, folder))
|
||||||
|
.join(path.delimiter);
|
||||||
|
|
||||||
|
// Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be
|
||||||
|
// injected into the application via DefinePlugin in webpack configuration.
|
||||||
|
const REACT_APP = /^REACT_APP_/i;
|
||||||
|
|
||||||
|
function getClientEnvironment(publicUrl) {
|
||||||
|
const raw = Object.keys(process.env)
|
||||||
|
.filter((key) => REACT_APP.test(key))
|
||||||
|
.reduce(
|
||||||
|
(env, key) => {
|
||||||
|
env[key] = process.env[key];
|
||||||
|
return env;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Useful for determining whether we’re running in production mode.
|
||||||
|
// Most importantly, it switches React into the correct mode.
|
||||||
|
NODE_ENV: process.env.NODE_ENV || 'development',
|
||||||
|
// Useful for resolving the correct path to static assets in `public`.
|
||||||
|
// For example, <img src={process.env.PUBLIC_URL + '/img/logo.png'} />.
|
||||||
|
// This should only be used as an escape hatch. Normally you would put
|
||||||
|
// images into the `src` and `import` them in code to get their paths.
|
||||||
|
PUBLIC_URL: publicUrl,
|
||||||
|
// We support configuring the sockjs pathname during development.
|
||||||
|
// These settings let a developer run multiple simultaneous projects.
|
||||||
|
// They are used as the connection `hostname`, `pathname` and `port`
|
||||||
|
// in webpackHotDevClient. They are used as the `sockHost`, `sockPath`
|
||||||
|
// and `sockPort` options in webpack-dev-server.
|
||||||
|
WDS_SOCKET_HOST: process.env.WDS_SOCKET_HOST,
|
||||||
|
WDS_SOCKET_PATH: process.env.WDS_SOCKET_PATH,
|
||||||
|
WDS_SOCKET_PORT: process.env.WDS_SOCKET_PORT,
|
||||||
|
// Whether or not react-refresh is enabled.
|
||||||
|
// react-refresh is not 100% stable at this time,
|
||||||
|
// which is why it's disabled by default.
|
||||||
|
// It is defined here so it is available in the webpackHotDevClient.
|
||||||
|
FAST_REFRESH: process.env.FAST_REFRESH !== 'false',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// Stringify all values so we can feed into webpack DefinePlugin
|
||||||
|
const stringified = {
|
||||||
|
'process.env': Object.keys(raw).reduce((env, key) => {
|
||||||
|
env[key] = JSON.stringify(raw[key]);
|
||||||
|
return env;
|
||||||
|
}, {}),
|
||||||
|
};
|
||||||
|
|
||||||
|
return { raw, stringified };
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = getClientEnvironment;
|
||||||
70
config/getHttpsConfig.js
Normal file
70
config/getHttpsConfig.js
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const crypto = require('crypto');
|
||||||
|
const chalk = require('react-dev-utils/chalk');
|
||||||
|
const paths = require('./paths');
|
||||||
|
|
||||||
|
// Ensure the certificate and key provided are valid and if not
|
||||||
|
// throw an easy to debug error
|
||||||
|
function validateKeyAndCerts({ cert, key, keyFile, crtFile }) {
|
||||||
|
let encrypted;
|
||||||
|
try {
|
||||||
|
// publicEncrypt will throw an error with an invalid cert
|
||||||
|
encrypted = crypto.publicEncrypt(cert, Buffer.from('test'));
|
||||||
|
} catch (err) {
|
||||||
|
throw new Error(
|
||||||
|
`The certificate "${chalk.yellow(crtFile)}" is invalid.\n${
|
||||||
|
err.message
|
||||||
|
}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// privateDecrypt will throw an error with an invalid key
|
||||||
|
crypto.privateDecrypt(key, encrypted);
|
||||||
|
} catch (err) {
|
||||||
|
throw new Error(
|
||||||
|
`The certificate key "${chalk.yellow(keyFile)}" is invalid.\n${
|
||||||
|
err.message
|
||||||
|
}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read file and throw an error if it doesn't exist
|
||||||
|
function readEnvFile(file, type) {
|
||||||
|
if (!fs.existsSync(file)) {
|
||||||
|
throw new Error(
|
||||||
|
`You specified ${chalk.cyan(
|
||||||
|
type
|
||||||
|
)} in your env, but the file "${chalk.yellow(
|
||||||
|
file
|
||||||
|
)}" can't be found.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return fs.readFileSync(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the https config
|
||||||
|
// Return cert files if provided in env, otherwise just true or false
|
||||||
|
function getHttpsConfig() {
|
||||||
|
const { SSL_CRT_FILE, SSL_KEY_FILE, HTTPS } = process.env;
|
||||||
|
const isHttps = HTTPS === 'true';
|
||||||
|
|
||||||
|
if (isHttps && SSL_CRT_FILE && SSL_KEY_FILE) {
|
||||||
|
const crtFile = path.resolve(paths.appPath, SSL_CRT_FILE);
|
||||||
|
const keyFile = path.resolve(paths.appPath, SSL_KEY_FILE);
|
||||||
|
const config = {
|
||||||
|
cert: readEnvFile(crtFile, 'SSL_CRT_FILE'),
|
||||||
|
key: readEnvFile(keyFile, 'SSL_KEY_FILE'),
|
||||||
|
};
|
||||||
|
|
||||||
|
validateKeyAndCerts({ ...config, keyFile, crtFile });
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
return isHttps;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = getHttpsConfig;
|
||||||
134
config/modules.js
Normal file
134
config/modules.js
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const paths = require('./paths');
|
||||||
|
const chalk = require('react-dev-utils/chalk');
|
||||||
|
const resolve = require('resolve');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get additional module paths based on the baseUrl of a compilerOptions object.
|
||||||
|
*
|
||||||
|
* @param {Object} options
|
||||||
|
*/
|
||||||
|
function getAdditionalModulePaths(options = {}) {
|
||||||
|
const baseUrl = options.baseUrl;
|
||||||
|
|
||||||
|
if (!baseUrl) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
|
||||||
|
|
||||||
|
// We don't need to do anything if `baseUrl` is set to `node_modules`. This is
|
||||||
|
// the default behavior.
|
||||||
|
if (path.relative(paths.appNodeModules, baseUrlResolved) === '') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow the user set the `baseUrl` to `appSrc`.
|
||||||
|
if (path.relative(paths.appSrc, baseUrlResolved) === '') {
|
||||||
|
return [paths.appSrc];
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the path is equal to the root directory we ignore it here.
|
||||||
|
// We don't want to allow importing from the root directly as source files are
|
||||||
|
// not transpiled outside of `src`. We do allow importing them with the
|
||||||
|
// absolute path (e.g. `src/Components/Button.js`) but we set that up with
|
||||||
|
// an alias.
|
||||||
|
if (path.relative(paths.appPath, baseUrlResolved) === '') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, throw an error.
|
||||||
|
throw new Error(
|
||||||
|
chalk.red.bold(
|
||||||
|
"Your project's `baseUrl` can only be set to `src` or `node_modules`." +
|
||||||
|
' Create React App does not support other values at this time.'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get webpack aliases based on the baseUrl of a compilerOptions object.
|
||||||
|
*
|
||||||
|
* @param {*} options
|
||||||
|
*/
|
||||||
|
function getWebpackAliases(options = {}) {
|
||||||
|
const baseUrl = options.baseUrl;
|
||||||
|
|
||||||
|
if (!baseUrl) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
|
||||||
|
|
||||||
|
if (path.relative(paths.appPath, baseUrlResolved) === '') {
|
||||||
|
return {
|
||||||
|
src: paths.appSrc,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get jest aliases based on the baseUrl of a compilerOptions object.
|
||||||
|
*
|
||||||
|
* @param {*} options
|
||||||
|
*/
|
||||||
|
function getJestAliases(options = {}) {
|
||||||
|
const baseUrl = options.baseUrl;
|
||||||
|
|
||||||
|
if (!baseUrl) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
|
||||||
|
|
||||||
|
if (path.relative(paths.appPath, baseUrlResolved) === '') {
|
||||||
|
return {
|
||||||
|
'^src/(.*)$': '<rootDir>/src/$1',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getModules() {
|
||||||
|
// Check if TypeScript is setup
|
||||||
|
const hasTsConfig = fs.existsSync(paths.appTsConfig);
|
||||||
|
const hasJsConfig = fs.existsSync(paths.appJsConfig);
|
||||||
|
|
||||||
|
if (hasTsConfig && hasJsConfig) {
|
||||||
|
throw new Error(
|
||||||
|
'You have both a tsconfig.json and a jsconfig.json. If you are using TypeScript please remove your jsconfig.json file.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let config;
|
||||||
|
|
||||||
|
// If there's a tsconfig.json we assume it's a
|
||||||
|
// TypeScript project and set up the config
|
||||||
|
// based on tsconfig.json
|
||||||
|
if (hasTsConfig) {
|
||||||
|
const ts = require(resolve.sync('typescript', {
|
||||||
|
basedir: paths.appNodeModules,
|
||||||
|
}));
|
||||||
|
config = ts.readConfigFile(paths.appTsConfig, ts.sys.readFile).config;
|
||||||
|
// Otherwise we'll check if there is jsconfig.json
|
||||||
|
// for non TS projects.
|
||||||
|
} else if (hasJsConfig) {
|
||||||
|
config = require(paths.appJsConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
config = config || {};
|
||||||
|
const options = config.compilerOptions || {};
|
||||||
|
|
||||||
|
const additionalModulePaths = getAdditionalModulePaths(options);
|
||||||
|
|
||||||
|
return {
|
||||||
|
additionalModulePaths: additionalModulePaths,
|
||||||
|
webpackAliases: getWebpackAliases(options),
|
||||||
|
jestAliases: getJestAliases(options),
|
||||||
|
hasTsConfig,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = getModules();
|
||||||
74
config/paths.js
Normal file
74
config/paths.js
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const path = require('path');
|
||||||
|
const fs = require('fs');
|
||||||
|
const getPublicUrlOrPath = require('react-dev-utils/getPublicUrlOrPath');
|
||||||
|
|
||||||
|
// Make sure any symlinks in the project folder are resolved:
|
||||||
|
// https://github.com/facebook/create-react-app/issues/637
|
||||||
|
const appDirectory = fs.realpathSync(process.cwd());
|
||||||
|
const resolveApp = (relativePath) => path.resolve(appDirectory, relativePath);
|
||||||
|
|
||||||
|
// We use `PUBLIC_URL` environment variable or "homepage" field to infer
|
||||||
|
// "public path" at which the app is served.
|
||||||
|
// webpack needs to know it to put the right <script> hrefs into HTML even in
|
||||||
|
// single-page apps that may serve index.html for nested URLs like /todos/42.
|
||||||
|
// We can't use a relative path in HTML because we don't want to load something
|
||||||
|
// like /todos/42/static/js/bundle.7289d.js. We have to know the root.
|
||||||
|
const publicUrlOrPath = getPublicUrlOrPath(
|
||||||
|
process.env.NODE_ENV === 'development',
|
||||||
|
require(resolveApp('package.json')).homepage,
|
||||||
|
process.env.PUBLIC_URL
|
||||||
|
);
|
||||||
|
|
||||||
|
const buildPath = process.env.BUILD_PATH || 'dist';
|
||||||
|
|
||||||
|
const moduleFileExtensions = [
|
||||||
|
'web.mjs',
|
||||||
|
'mjs',
|
||||||
|
'web.js',
|
||||||
|
'js',
|
||||||
|
'web.ts',
|
||||||
|
'ts',
|
||||||
|
'web.tsx',
|
||||||
|
'tsx',
|
||||||
|
'json',
|
||||||
|
'web.jsx',
|
||||||
|
'jsx',
|
||||||
|
];
|
||||||
|
|
||||||
|
// Resolve file paths in the same order as webpack
|
||||||
|
const resolveModule = (resolveFn, filePath) => {
|
||||||
|
const extension = moduleFileExtensions.find((extension) =>
|
||||||
|
fs.existsSync(resolveFn(`${filePath}.${extension}`))
|
||||||
|
);
|
||||||
|
|
||||||
|
if (extension) {
|
||||||
|
return resolveFn(`${filePath}.${extension}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolveFn(`${filePath}.js`);
|
||||||
|
};
|
||||||
|
|
||||||
|
// config after eject: we're in ./config/
|
||||||
|
module.exports = {
|
||||||
|
dotenv: resolveApp('.env'),
|
||||||
|
appPath: resolveApp('.'),
|
||||||
|
appBuild: resolveApp(buildPath),
|
||||||
|
appPublic: resolveApp('public'),
|
||||||
|
appHtml: resolveApp('public/index.html'),
|
||||||
|
appIndexJs: resolveModule(resolveApp, 'src/index'),
|
||||||
|
appEditorJs: resolveModule(resolveApp, 'src/editor'),
|
||||||
|
appPackageJson: resolveApp('package.json'),
|
||||||
|
appSrc: resolveApp('src'),
|
||||||
|
appTsConfig: resolveApp('tsconfig.json'),
|
||||||
|
appJsConfig: resolveApp('jsconfig.json'),
|
||||||
|
yarnLockFile: resolveApp('yarn.lock'),
|
||||||
|
testsSetup: resolveModule(resolveApp, 'src/setupTests'),
|
||||||
|
proxySetup: resolveApp('src/setupProxy.js'),
|
||||||
|
appNodeModules: resolveApp('node_modules'),
|
||||||
|
swSrc: resolveModule(resolveApp, 'src/service-worker'),
|
||||||
|
publicUrlOrPath,
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports.moduleFileExtensions = moduleFileExtensions;
|
||||||
35
config/pnpTs.js
Normal file
35
config/pnpTs.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { resolveModuleName } = require('ts-pnp');
|
||||||
|
|
||||||
|
exports.resolveModuleName = (
|
||||||
|
typescript,
|
||||||
|
moduleName,
|
||||||
|
containingFile,
|
||||||
|
compilerOptions,
|
||||||
|
resolutionHost
|
||||||
|
) => {
|
||||||
|
return resolveModuleName(
|
||||||
|
moduleName,
|
||||||
|
containingFile,
|
||||||
|
compilerOptions,
|
||||||
|
resolutionHost,
|
||||||
|
typescript.resolveModuleName
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.resolveTypeReferenceDirective = (
|
||||||
|
typescript,
|
||||||
|
moduleName,
|
||||||
|
containingFile,
|
||||||
|
compilerOptions,
|
||||||
|
resolutionHost
|
||||||
|
) => {
|
||||||
|
return resolveModuleName(
|
||||||
|
moduleName,
|
||||||
|
containingFile,
|
||||||
|
compilerOptions,
|
||||||
|
resolutionHost,
|
||||||
|
typescript.resolveTypeReferenceDirective
|
||||||
|
);
|
||||||
|
};
|
||||||
621
config/webpack.config.js
Normal file
621
config/webpack.config.js
Normal file
@@ -0,0 +1,621 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const webpack = require('webpack');
|
||||||
|
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
|
||||||
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
|
const TerserPlugin = require('terser-webpack-plugin');
|
||||||
|
const PnpWebpackPlugin = require('pnp-webpack-plugin');
|
||||||
|
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||||
|
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
|
||||||
|
const { WebpackManifestPlugin } = require('webpack-manifest-plugin');
|
||||||
|
const InlineChunkHtmlPlugin = require('react-dev-utils/InlineChunkHtmlPlugin');
|
||||||
|
const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
|
||||||
|
const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin');
|
||||||
|
// const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
|
||||||
|
const WorkboxWebpackPlugin = require('workbox-webpack-plugin');
|
||||||
|
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
|
||||||
|
const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent');
|
||||||
|
|
||||||
|
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
||||||
|
const SpeedMeasurePlugin = require('speed-measure-webpack-plugin');
|
||||||
|
const smp = new SpeedMeasurePlugin();
|
||||||
|
|
||||||
|
const apiMocker = require('mocker-api');
|
||||||
|
const paths = require('./paths');
|
||||||
|
const modules = require('./modules');
|
||||||
|
const getClientEnvironment = require('./env');
|
||||||
|
|
||||||
|
// Source maps are resource heavy and can cause out of memory issue for large source files.
|
||||||
|
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false';
|
||||||
|
const shouldInlineRuntimeChunk = process.env.INLINE_RUNTIME_CHUNK !== 'false';
|
||||||
|
|
||||||
|
const webpackDevClientEntry = require.resolve(
|
||||||
|
'react-dev-utils/webpackHotDevClient'
|
||||||
|
);
|
||||||
|
const reactRefreshOverlayEntry = require.resolve(
|
||||||
|
'react-dev-utils/refreshOverlayInterop'
|
||||||
|
);
|
||||||
|
|
||||||
|
const imageInlineSizeLimit = parseInt(
|
||||||
|
process.env.IMAGE_INLINE_SIZE_LIMIT || '10000'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Get the path to the uncompiled service worker (if it exists).
|
||||||
|
const swSrc = paths.swSrc;
|
||||||
|
|
||||||
|
const cssRegex = /\.css$/;
|
||||||
|
const cssModuleRegex = /\.module\.css$/;
|
||||||
|
const sassRegex = /\.(scss|sass)$/;
|
||||||
|
const sassModuleRegex = /\.module\.(scss|sass)$/;
|
||||||
|
|
||||||
|
webpackConfig = function (webpackEnv) {
|
||||||
|
const isEnvDevelopment = webpackEnv === 'development';
|
||||||
|
const isEnvProduction = webpackEnv === 'production';
|
||||||
|
|
||||||
|
// Variable used for enabling profiling in Production
|
||||||
|
// passed into alias object. Uses a flag if passed into the build command
|
||||||
|
const isEnvProductionProfile =
|
||||||
|
isEnvProduction && process.argv.includes('--profile');
|
||||||
|
|
||||||
|
// We will provide `paths.publicUrlOrPath` to our app
|
||||||
|
// as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript.
|
||||||
|
// Omit trailing slash as %PUBLIC_URL%/xyz looks better than %PUBLIC_URL%xyz.
|
||||||
|
// Get environment variables to inject into our app.
|
||||||
|
const env = getClientEnvironment(paths.publicUrlOrPath.slice(0, -1));
|
||||||
|
|
||||||
|
const shouldUseReactRefresh = true;//env.raw.FAST_REFRESH;
|
||||||
|
|
||||||
|
const getStyleLoaders = (cssOptions, preProcessor) => {
|
||||||
|
const loaders = [
|
||||||
|
isEnvDevelopment && require.resolve('style-loader'),
|
||||||
|
isEnvProduction && {
|
||||||
|
loader: MiniCssExtractPlugin.loader,
|
||||||
|
// css is located in `static/css`, use '../../' to locate index.html folder
|
||||||
|
// in production `paths.publicUrlOrPath` can be a relative path
|
||||||
|
options: paths.publicUrlOrPath.startsWith('.')
|
||||||
|
? { publicPath: '../../' }
|
||||||
|
: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
loader: require.resolve('css-loader'),
|
||||||
|
options: cssOptions,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Options for PostCSS as we reference these options twice
|
||||||
|
// Adds vendor prefixing based on your specified browser support in
|
||||||
|
// package.json
|
||||||
|
loader: require.resolve('postcss-loader'),
|
||||||
|
},
|
||||||
|
].filter(Boolean);
|
||||||
|
if (preProcessor) {
|
||||||
|
loaders.push(
|
||||||
|
{
|
||||||
|
loader: require.resolve('resolve-url-loader'),
|
||||||
|
options: {
|
||||||
|
sourceMap: isEnvProduction
|
||||||
|
? shouldUseSourceMap
|
||||||
|
: isEnvDevelopment,
|
||||||
|
root: paths.appSrc,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
loader: require.resolve(preProcessor),
|
||||||
|
options: {
|
||||||
|
sourceMap: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return loaders;
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
mode: isEnvProduction
|
||||||
|
? 'production'
|
||||||
|
: isEnvDevelopment && 'development',
|
||||||
|
context: path.resolve(__dirname, '../'),
|
||||||
|
entry: {
|
||||||
|
main:
|
||||||
|
isEnvDevelopment && !shouldUseReactRefresh
|
||||||
|
? [
|
||||||
|
// Include an alternative client for WebpackDevServer. A client's job is to
|
||||||
|
// connect to WebpackDevServer by a socket and get notified about changes.
|
||||||
|
// When you save a file, the client will either apply hot updates (in case
|
||||||
|
// of CSS changes), or refresh the page (in case of JS changes). When you
|
||||||
|
// make a syntax error, this client will display a syntax error overlay.
|
||||||
|
// Note: instead of the default WebpackDevServer client, we use a custom one
|
||||||
|
// to bring better experience for Create React App users. You can replace
|
||||||
|
// the line below with these two lines if you prefer the stock client:
|
||||||
|
//
|
||||||
|
// require.resolve('webpack-dev-server/client') + '?/',
|
||||||
|
// require.resolve('webpack/hot/dev-server'),
|
||||||
|
//
|
||||||
|
// When using the experimental react-refresh integration,
|
||||||
|
// the webpack plugin takes care of injecting the dev client for us.
|
||||||
|
webpackDevClientEntry,
|
||||||
|
// Finally, this is your app's code:
|
||||||
|
paths.appIndexJs,
|
||||||
|
// We include the app code last so that if there is a runtime error during
|
||||||
|
// initialization, it doesn't blow up the WebpackDevServer client, and
|
||||||
|
// changing JS code would still trigger a refresh.
|
||||||
|
]
|
||||||
|
: paths.appIndexJs
|
||||||
|
// 'editor.worker': 'monaco-editor/esm/vs/editor/editor.worker.js',
|
||||||
|
// 'json.worker': 'monaco-editor/esm/vs/language/json/json.worker',
|
||||||
|
// 'css.worker': 'monaco-editor/esm/vs/language/css/css.worker',
|
||||||
|
// 'html.worker': 'monaco-editor/esm/vs/language/html/html.worker',
|
||||||
|
// 'ts.worker': 'monaco-editor/esm/vs/language/typescript/ts.worker',
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
// The build folder.
|
||||||
|
path: isEnvProduction ? paths.appBuild : undefined,
|
||||||
|
// Add /* filename */ comments to generated require()s in the output.
|
||||||
|
pathinfo: isEnvDevelopment,
|
||||||
|
// There will be one main bundle, and one file per asynchronous chunk.
|
||||||
|
// In development, it does not produce real files.
|
||||||
|
filename: isEnvProduction
|
||||||
|
? 'static/js/[name].[contenthash:8].js'
|
||||||
|
: isEnvDevelopment && 'static/js/[name].bundle.js',
|
||||||
|
|
||||||
|
// There are also additional JS chunk files if you use code splitting.
|
||||||
|
chunkFilename: isEnvProduction
|
||||||
|
? 'static/js/[name].[contenthash:8].chunk.js'
|
||||||
|
: isEnvDevelopment && 'static/js/[name].chunk.js',
|
||||||
|
// webpack uses `publicPath` to determine where the app is being served from.
|
||||||
|
// It requires a trailing slash, or the file assets will get an incorrect path.
|
||||||
|
// We inferred the "public path" (such as / or /my-project) from homepage.
|
||||||
|
publicPath: paths.publicUrlOrPath,
|
||||||
|
// Point sourcemap entries to original disk location (format as URL on Windows)
|
||||||
|
devtoolModuleFilenameTemplate: isEnvProduction
|
||||||
|
? (info) =>
|
||||||
|
path
|
||||||
|
.relative(paths.appSrc, info.absoluteResourcePath)
|
||||||
|
.replace(/\\/g, '/')
|
||||||
|
: isEnvDevelopment &&
|
||||||
|
((info) =>
|
||||||
|
path
|
||||||
|
.resolve(info.absoluteResourcePath)
|
||||||
|
.replace(/\\/g, '/')),
|
||||||
|
},
|
||||||
|
optimization: {
|
||||||
|
minimize: true,
|
||||||
|
minimizer: [
|
||||||
|
// This is only used in production mode
|
||||||
|
new TerserPlugin({
|
||||||
|
terserOptions: {
|
||||||
|
parse: {
|
||||||
|
// We want terser to parse ecma 8 code. However, we don't want it
|
||||||
|
// to apply any minification steps that turns valid ecma 5 code
|
||||||
|
// into invalid ecma 5 code. This is why the 'compress' and 'output'
|
||||||
|
// sections only apply transformations that are ecma 5 safe
|
||||||
|
// https://github.com/facebook/create-react-app/pull/4234
|
||||||
|
ecma: 8,
|
||||||
|
},
|
||||||
|
compress: {
|
||||||
|
ecma: 5,
|
||||||
|
warnings: false,
|
||||||
|
// Disabled because of an issue with Uglify breaking seemingly valid code:
|
||||||
|
// https://github.com/facebook/create-react-app/issues/2376
|
||||||
|
// Pending further investigation:
|
||||||
|
// https://github.com/mishoo/UglifyJS2/issues/2011
|
||||||
|
comparisons: false,
|
||||||
|
// Disabled because of an issue with Terser breaking valid code:
|
||||||
|
// https://github.com/facebook/create-react-app/issues/5250
|
||||||
|
// Pending further investigation:
|
||||||
|
// https://github.com/terser-js/terser/issues/120
|
||||||
|
inline: 2,
|
||||||
|
},
|
||||||
|
mangle: {
|
||||||
|
safari10: true,
|
||||||
|
},
|
||||||
|
// Added for profiling in devtools
|
||||||
|
// keep_classnames: isEnvProductionProfile,
|
||||||
|
// keep_fnames: isEnvProductionProfile,
|
||||||
|
output: {
|
||||||
|
ecma: 5,
|
||||||
|
comments: false,
|
||||||
|
// Turned on because emoji and regex is not minified properly using default
|
||||||
|
// https://github.com/facebook/create-react-app/issues/2488
|
||||||
|
ascii_only: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
// This is only used in production mode
|
||||||
|
new CssMinimizerPlugin({
|
||||||
|
minimizerOptions: {
|
||||||
|
preset: [
|
||||||
|
'default',
|
||||||
|
{ minifyFontValues: { removeQuotes: false } },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
// Automatically split vendor and commons
|
||||||
|
// https://twitter.com/wSokra/status/969633336732905474
|
||||||
|
// https://medium.com/webpack/webpack-4-code-splitting-chunk-graph-and-the-splitchunks-optimization-be739a861366
|
||||||
|
splitChunks: {
|
||||||
|
chunks: 'all',
|
||||||
|
name: false,
|
||||||
|
},
|
||||||
|
// Keep the runtime chunk separated to enable long term caching
|
||||||
|
// https://twitter.com/wSokra/status/969679223278505985
|
||||||
|
// https://github.com/facebook/create-react-app/issues/5358
|
||||||
|
runtimeChunk: {
|
||||||
|
name: (entrypoint) => `runtime-${entrypoint.name}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.tsx', '.ts', '.js', '.html', '.mjs'],
|
||||||
|
alias: {
|
||||||
|
'@': path.resolve(__dirname, '..', 'src'),
|
||||||
|
},
|
||||||
|
fallback: {
|
||||||
|
"util": false,
|
||||||
|
"path": false,
|
||||||
|
"stream": false,
|
||||||
|
"url": require.resolve('url')
|
||||||
|
},
|
||||||
|
conditionNames: ['require', 'browser', 'web'],
|
||||||
|
// This allows you to set a fallback for where webpack should look for modules.
|
||||||
|
// We placed these paths second because we want `node_modules` to "win"
|
||||||
|
// if there are any conflicts. This matches Node resolution mechanism.
|
||||||
|
// https://github.com/facebook/create-react-app/issues/253
|
||||||
|
modules: ['node_modules', paths.appNodeModules].concat(
|
||||||
|
modules.additionalModulePaths || []
|
||||||
|
),
|
||||||
|
plugins: [
|
||||||
|
// Adds support for installing with Plug'n'Play, leading to faster installs and adding
|
||||||
|
// guards against forgotten dependencies and such.
|
||||||
|
PnpWebpackPlugin,
|
||||||
|
// Prevents users from importing files from outside of src/ (or node_modules/).
|
||||||
|
// This often causes confusion because we only process files within src/ with babel.
|
||||||
|
// To fix this, we prevent you from importing files out of src/ -- if you'd like to,
|
||||||
|
// please link the files into your node_modules/ and let module-resolution kick in.
|
||||||
|
// Make sure your source files are compiled, as they will not be processed in any way.
|
||||||
|
// new ModuleScopePlugin(paths.appSrc, [
|
||||||
|
// paths.appPackageJson,
|
||||||
|
// reactRefreshOverlayEntry,
|
||||||
|
// ]),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
resolveLoader: {
|
||||||
|
plugins: [
|
||||||
|
// Also related to Plug'n'Play, but this time it tells webpack to load its loaders
|
||||||
|
// from the current package.
|
||||||
|
PnpWebpackPlugin.moduleLoader(module),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
// Disable require.ensure as it's not a standard language feature.
|
||||||
|
// { parser: { requireEnsure: false } },
|
||||||
|
{
|
||||||
|
oneOf: [
|
||||||
|
// {
|
||||||
|
// test: /froala-editor/,
|
||||||
|
// parser: {
|
||||||
|
// amd: false,
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
|
||||||
|
loader: require.resolve('url-loader'),
|
||||||
|
options: {
|
||||||
|
limit: imageInlineSizeLimit,
|
||||||
|
name: 'static/media/[name].[hash:8].[ext]',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// Process application JS with Babel.
|
||||||
|
// The preset includes JSX, Flow, TypeScript, and some ESnext features.
|
||||||
|
{
|
||||||
|
test: /\.(js|cjs|mjs|jsx|ts|tsx)$/,
|
||||||
|
include: paths.appSrc,
|
||||||
|
loader: require.resolve('babel-loader'),
|
||||||
|
options: {
|
||||||
|
plugins: [
|
||||||
|
// [
|
||||||
|
// require.resolve('babel-plugin-named-asset-import'),
|
||||||
|
// {
|
||||||
|
// loaderMap: {
|
||||||
|
// svg: {
|
||||||
|
// ReactComponent:
|
||||||
|
// '@svgr/webpack?-svgo,+titleProp,+ref![path]',
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
isEnvDevelopment &&
|
||||||
|
shouldUseReactRefresh &&
|
||||||
|
require.resolve('react-refresh/babel'),
|
||||||
|
].filter(Boolean),
|
||||||
|
cacheDirectory: true,
|
||||||
|
compact: isEnvProduction,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// "postcss" loader applies autoprefixer to our CSS.
|
||||||
|
// "css" loader resolves paths in CSS and adds assets as dependencies.
|
||||||
|
// "style" loader turns CSS into JS modules that inject <style> tags.
|
||||||
|
// In production, we use MiniCSSExtractPlugin to extract that CSS
|
||||||
|
// to a file, but in development "style" loader enables hot editing
|
||||||
|
// of CSS.
|
||||||
|
// By default we support CSS Modules with the extension .module.css
|
||||||
|
{
|
||||||
|
test: cssRegex,
|
||||||
|
exclude: cssModuleRegex,
|
||||||
|
use: getStyleLoaders({
|
||||||
|
importLoaders: 1,
|
||||||
|
sourceMap: isEnvProduction
|
||||||
|
? shouldUseSourceMap
|
||||||
|
: isEnvDevelopment,
|
||||||
|
}),
|
||||||
|
// Don't consider CSS imports dead code even if the
|
||||||
|
// containing package claims to have no side effects.
|
||||||
|
// Remove this when webpack adds a warning or an error for this.
|
||||||
|
// See https://github.com/webpack/webpack/issues/6571
|
||||||
|
sideEffects: true,
|
||||||
|
},
|
||||||
|
// Adds support for CSS Modules (https://github.com/css-modules/css-modules)
|
||||||
|
// using the extension .module.css
|
||||||
|
{
|
||||||
|
test: cssModuleRegex,
|
||||||
|
use: getStyleLoaders({
|
||||||
|
importLoaders: 1,
|
||||||
|
sourceMap: isEnvProduction
|
||||||
|
? shouldUseSourceMap
|
||||||
|
: isEnvDevelopment,
|
||||||
|
modules: {
|
||||||
|
getLocalIdent: getCSSModuleLocalIdent,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
// Opt-in support for SASS (using .scss or .sass extensions).
|
||||||
|
// By default we support SASS Modules with the
|
||||||
|
// extensions .module.scss or .module.sass
|
||||||
|
{
|
||||||
|
test: sassRegex,
|
||||||
|
exclude: sassModuleRegex,
|
||||||
|
use: getStyleLoaders(
|
||||||
|
{
|
||||||
|
importLoaders: 3,
|
||||||
|
sourceMap: isEnvProduction
|
||||||
|
? shouldUseSourceMap
|
||||||
|
: isEnvDevelopment,
|
||||||
|
},
|
||||||
|
'sass-loader'
|
||||||
|
),
|
||||||
|
// Don't consider CSS imports dead code even if the
|
||||||
|
// containing package claims to have no side effects.
|
||||||
|
// Remove this when webpack adds a warning or an error for this.
|
||||||
|
// See https://github.com/webpack/webpack/issues/6571
|
||||||
|
sideEffects: true,
|
||||||
|
},
|
||||||
|
// Adds support for CSS Modules, but using SASS
|
||||||
|
// using the extension .module.scss or .module.sass
|
||||||
|
{
|
||||||
|
test: sassModuleRegex,
|
||||||
|
use: getStyleLoaders(
|
||||||
|
{
|
||||||
|
importLoaders: 3,
|
||||||
|
sourceMap: isEnvProduction
|
||||||
|
? shouldUseSourceMap
|
||||||
|
: isEnvDevelopment,
|
||||||
|
modules: {
|
||||||
|
getLocalIdent: getCSSModuleLocalIdent,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'sass-loader'
|
||||||
|
),
|
||||||
|
},
|
||||||
|
// "file" loader makes sure those assets get served by WebpackDevServer.
|
||||||
|
// When you `import` an asset, you get its (virtual) filename.
|
||||||
|
// In production, they would get copied to the `build` folder.
|
||||||
|
// This loader doesn't use a "test" so it will catch all modules
|
||||||
|
// that fall through the other loaders.
|
||||||
|
{
|
||||||
|
loader: require.resolve('file-loader'),
|
||||||
|
// Exclude `js` files to keep "css" loader working as it injects
|
||||||
|
// its runtime that would otherwise be processed through "file" loader.
|
||||||
|
// Also exclude `html` and `json` extensions so they get processed
|
||||||
|
// by webpacks internal loaders.
|
||||||
|
exclude: [
|
||||||
|
/\.(js|cjs|mjs|jsx|ts|tsx)$/,
|
||||||
|
/\.html$/,
|
||||||
|
/\.json$/,
|
||||||
|
],
|
||||||
|
options: {
|
||||||
|
name: 'static/media/[name].[hash:8].[ext]',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
// Generates an `index.html` file with the <script> injected.
|
||||||
|
new HtmlWebpackPlugin(
|
||||||
|
Object.assign(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
inject: true,
|
||||||
|
template: paths.appHtml,
|
||||||
|
},
|
||||||
|
isEnvProduction
|
||||||
|
? {
|
||||||
|
minify: {
|
||||||
|
removeComments: true,
|
||||||
|
collapseWhitespace: true,
|
||||||
|
removeRedundantAttributes: true,
|
||||||
|
useShortDoctype: true,
|
||||||
|
removeEmptyAttributes: true,
|
||||||
|
removeStyleLinkTypeAttributes: true,
|
||||||
|
keepClosingSlash: true,
|
||||||
|
minifyJS: true,
|
||||||
|
minifyCSS: true,
|
||||||
|
minifyURLs: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
|
)
|
||||||
|
),
|
||||||
|
// Inlines the webpack runtime script. This script is too small to warrant
|
||||||
|
// a network request.
|
||||||
|
// https://github.com/facebook/create-react-app/issues/5358
|
||||||
|
isEnvProduction &&
|
||||||
|
shouldInlineRuntimeChunk &&
|
||||||
|
new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [
|
||||||
|
/runtime-.+[.]js/,
|
||||||
|
]),
|
||||||
|
// Makes some environment variables available in index.html.
|
||||||
|
// The public URL is available as %PUBLIC_URL% in index.html, e.g.:
|
||||||
|
// <link rel="icon" href="%PUBLIC_URL%/favicon.ico">
|
||||||
|
// It will be an empty string unless you specify "homepage"
|
||||||
|
// in `package.json`, in which case it will be the pathname of that URL.
|
||||||
|
new InterpolateHtmlPlugin(HtmlWebpackPlugin, env.raw),
|
||||||
|
// This gives some necessary context to module not found errors, such as
|
||||||
|
// the requesting resource.
|
||||||
|
new ModuleNotFoundPlugin(paths.appPath),
|
||||||
|
// Makes some environment variables available to the JS code, for example:
|
||||||
|
// if (process.env.NODE_ENV === 'production') { ... }. See `./env.js`.
|
||||||
|
// It is absolutely essential that NODE_ENV is set to production
|
||||||
|
// during a production build.
|
||||||
|
// Otherwise React will be compiled in the very slow development mode.
|
||||||
|
new webpack.DefinePlugin(env.stringified),
|
||||||
|
// This is necessary to emit hot updates (CSS and Fast Refresh):
|
||||||
|
isEnvDevelopment && new webpack.HotModuleReplacementPlugin(),
|
||||||
|
// Experimental hot reloading for React .
|
||||||
|
// https://github.com/facebook/react/tree/master/packages/react-refresh
|
||||||
|
isEnvDevelopment &&
|
||||||
|
shouldUseReactRefresh &&
|
||||||
|
new ReactRefreshWebpackPlugin({
|
||||||
|
overlay: {
|
||||||
|
entry: webpackDevClientEntry,
|
||||||
|
// The expected exports are slightly different from what the overlay exports,
|
||||||
|
// so an interop is included here to enable feedback on module-level errors.
|
||||||
|
module: reactRefreshOverlayEntry,
|
||||||
|
// Since we ship a custom dev client and overlay integration,
|
||||||
|
// the bundled socket handling logic can be eliminated.
|
||||||
|
sockIntegration: false,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
// Watcher doesn't work well if you mistype casing in a path so we use
|
||||||
|
// a plugin that prints an error when you attempt to do this.
|
||||||
|
// See https://github.com/facebook/create-react-app/issues/240
|
||||||
|
isEnvDevelopment && new CaseSensitivePathsPlugin(),
|
||||||
|
isEnvProduction &&
|
||||||
|
new MiniCssExtractPlugin({
|
||||||
|
// Options similar to the same options in webpackOptions.output
|
||||||
|
// both options are optional
|
||||||
|
filename: 'static/css/[name].[contenthash:8].css',
|
||||||
|
chunkFilename:
|
||||||
|
'static/css/[name].[contenthash:8].chunk.css',
|
||||||
|
}),
|
||||||
|
// Generate an asset manifest file with the following content:
|
||||||
|
// - "files" key: Mapping of all asset filenames to their corresponding
|
||||||
|
// output file so that tools can pick it up without having to parse
|
||||||
|
// `index.html`
|
||||||
|
// - "entrypoints" key: Array of files which are included in `index.html`,
|
||||||
|
// can be used to reconstruct the HTML if necessary
|
||||||
|
new WebpackManifestPlugin({
|
||||||
|
fileName: 'asset-manifest.json',
|
||||||
|
publicPath: paths.publicUrlOrPath,
|
||||||
|
generate: (seed, files, entrypoints) => {
|
||||||
|
const manifestFiles = files.reduce((manifest, file) => {
|
||||||
|
manifest[file.name] = file.path;
|
||||||
|
return manifest;
|
||||||
|
}, seed);
|
||||||
|
const entrypointFiles = entrypoints.main.filter(
|
||||||
|
(fileName) => !fileName.endsWith('.map')
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
files: manifestFiles,
|
||||||
|
entrypoints: entrypointFiles,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
// Moment.js is an extremely popular library that bundles large locale files
|
||||||
|
// by default due to how webpack interprets its code. This is a practical
|
||||||
|
// solution that requires the user to opt into importing specific locales.
|
||||||
|
// https://github.com/jmblog/how-to-optimize-momentjs-with-webpack
|
||||||
|
// You can remove this if you don't use Moment.js:
|
||||||
|
new webpack.IgnorePlugin({
|
||||||
|
resourceRegExp: /^\.\/locale$/,
|
||||||
|
contextRegExp: /moment$/,
|
||||||
|
}),
|
||||||
|
isEnvProduction &&
|
||||||
|
fs.existsSync(swSrc) &&
|
||||||
|
new WorkboxWebpackPlugin.InjectManifest({
|
||||||
|
swSrc,
|
||||||
|
dontCacheBustURLsMatching: /\.[0-9a-f]{8}\./,
|
||||||
|
exclude: [/\.map$/, /asset-manifest\.json$/, /LICENSE/],
|
||||||
|
// Bump up the default maximum size (2mb) that's precached,
|
||||||
|
// to make lazy-loading failure scenarios less likely.
|
||||||
|
// See https://github.com/cra-template/pwa/issues/13#issuecomment-722667270
|
||||||
|
maximumFileSizeToCacheInBytes: 5 * 1024 * 1024,
|
||||||
|
}),
|
||||||
|
// useTypeScript &&
|
||||||
|
// new ForkTsCheckerWebpackPlugin({
|
||||||
|
// typescript: resolve.sync('typescript', {
|
||||||
|
// basedir: paths.appNodeModules,
|
||||||
|
// }),
|
||||||
|
// async: isEnvDevelopment,
|
||||||
|
// checkSyntacticErrors: true,
|
||||||
|
// resolveModuleNameModule: process.versions.pnp
|
||||||
|
// ? `${__dirname}/pnpTs.js`
|
||||||
|
// : undefined,
|
||||||
|
// resolveTypeReferenceDirectiveModule: process.versions.pnp
|
||||||
|
// ? `${__dirname}/pnpTs.js`
|
||||||
|
// : undefined,
|
||||||
|
// tsconfig: paths.appTsConfig,
|
||||||
|
// reportFiles: [
|
||||||
|
// // This one is specifically to match during CI tests,
|
||||||
|
// // as micromatch doesn't match
|
||||||
|
// // '../cra-template-typescript/template/src/App.tsx'
|
||||||
|
// // otherwise.
|
||||||
|
// '../**/src/**/*.{ts,tsx}',
|
||||||
|
// '**/src/**/*.{ts,tsx}',
|
||||||
|
// '!**/src/**/__tests__/**',
|
||||||
|
// '!**/src/**/?(*.)(spec|test).*',
|
||||||
|
// '!**/src/setupProxy.*',
|
||||||
|
// '!**/src/setupTests.*',
|
||||||
|
// ],
|
||||||
|
// silent: true,
|
||||||
|
// // The formatter is invoked directly in WebpackDevServerUtils during development
|
||||||
|
// formatter: isEnvProduction ? typescriptFormatter : undefined,
|
||||||
|
// }),
|
||||||
|
// !disableESLintPlugin &&
|
||||||
|
// new ESLintPlugin({
|
||||||
|
// // Plugin options
|
||||||
|
// extensions: ['js', 'mjs', 'jsx', 'ts', 'tsx'],
|
||||||
|
// formatter: require.resolve('react-dev-utils/eslintFormatter'),
|
||||||
|
// eslintPath: require.resolve('eslint'),
|
||||||
|
// failOnError: !(isEnvDevelopment && emitErrorsAsWarnings),
|
||||||
|
// context: paths.appSrc,
|
||||||
|
// cache: true,
|
||||||
|
// cacheLocation: path.resolve(
|
||||||
|
// paths.appNodeModules,
|
||||||
|
// '.cache/.eslintcache'
|
||||||
|
// ),
|
||||||
|
// // ESLint class options
|
||||||
|
// cwd: paths.appPath,
|
||||||
|
// resolvePluginsRelativeTo: __dirname,
|
||||||
|
// baseConfig: {
|
||||||
|
// extends: [require.resolve('eslint-config-react-app/base')],
|
||||||
|
// rules: {
|
||||||
|
// ...(!hasJsxRuntime && {
|
||||||
|
// 'react/react-in-jsx-scope': 'error',
|
||||||
|
// }),
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// }),
|
||||||
|
isEnvProduction && new BundleAnalyzerPlugin({ analyzerMode: 'static', generateStatsFile: true })
|
||||||
|
].filter(Boolean),
|
||||||
|
// Turn off performance processing because we utilize
|
||||||
|
// our own hints via the FileSizeReporter
|
||||||
|
performance: false,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = webpackConfig;
|
||||||
|
// 打印每个模块的执行速度
|
||||||
|
// https://github.com/stephencookdev/speed-measure-webpack-plugin/issues/167
|
||||||
|
// module.exports = smp.wrap(webpackConfig);
|
||||||
79
config/webpackDevServer.config.js
Normal file
79
config/webpackDevServer.config.js
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const evalSourceMapMiddleware = require('react-dev-utils/evalSourceMapMiddleware');
|
||||||
|
const noopServiceWorkerMiddleware = require('react-dev-utils/noopServiceWorkerMiddleware');
|
||||||
|
const ignoredFiles = require('react-dev-utils/ignoredFiles');
|
||||||
|
const redirectServedPath = require('react-dev-utils/redirectServedPathMiddleware');
|
||||||
|
const paths = require('./paths');
|
||||||
|
const getHttpsConfig = require('./getHttpsConfig');
|
||||||
|
|
||||||
|
const host = process.env.HOST || '0.0.0.0';
|
||||||
|
const sockHost = process.env.WDS_SOCKET_HOST;
|
||||||
|
const sockPath = process.env.WDS_SOCKET_PATH; // default: '/sockjs-node'
|
||||||
|
const sockPort = process.env.WDS_SOCKET_PORT;
|
||||||
|
|
||||||
|
module.exports = function (proxy, allowedHost) {
|
||||||
|
const disableFirewall =
|
||||||
|
!proxy || process.env.DANGEROUSLY_DISABLE_HOST_CHECK === "true";
|
||||||
|
return {
|
||||||
|
allowedHosts: disableFirewall ? "all" : [allowedHost],
|
||||||
|
compress: true,
|
||||||
|
static: {
|
||||||
|
directory: paths.appPublic,
|
||||||
|
publicPath: paths.publicUrlOrPath,
|
||||||
|
watch: {
|
||||||
|
ignored: ignoredFiles(paths.appSrc),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
client: {
|
||||||
|
webSocketURL: {
|
||||||
|
hostname: sockHost,
|
||||||
|
pathname: sockPath,
|
||||||
|
port: sockPort,
|
||||||
|
},
|
||||||
|
overlay: true,
|
||||||
|
},
|
||||||
|
devMiddleware: {
|
||||||
|
// It is important to tell WebpackDevServer to use the same "publicPath" path as
|
||||||
|
// we specified in the webpack config. When homepage is '.', default to serving
|
||||||
|
// from the root.
|
||||||
|
// remove last slash so user can land on `/test` instead of `/test/`
|
||||||
|
publicPath: paths.publicUrlOrPath.slice(0, -1),
|
||||||
|
},
|
||||||
|
https: getHttpsConfig(),
|
||||||
|
host,
|
||||||
|
historyApiFallback: {
|
||||||
|
// Paths with dots should still use the history fallback.
|
||||||
|
// See https://github.com/facebook/create-react-app/issues/387.
|
||||||
|
disableDotRule: true,
|
||||||
|
index: paths.publicUrlOrPath,
|
||||||
|
},
|
||||||
|
// `proxy` is run between `before` and `after` `webpack-dev-server` hooks
|
||||||
|
proxy,
|
||||||
|
onBeforeSetupMiddleware(server) {
|
||||||
|
const app = server.app;
|
||||||
|
// Keep `evalSourceMapMiddleware`
|
||||||
|
// middlewares before `redirectServedPath` otherwise will not have any effect
|
||||||
|
// This lets us fetch source contents from webpack for the error overlay
|
||||||
|
app.use(evalSourceMapMiddleware(server));
|
||||||
|
|
||||||
|
if (fs.existsSync(paths.proxySetup)) {
|
||||||
|
// This registers user provided middleware for proxy reasons
|
||||||
|
require(paths.proxySetup)(app);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onAfterSetupMiddleware(server) {
|
||||||
|
const app = server.app;
|
||||||
|
// Redirect to `PUBLIC_URL` or `homepage` from `package.json` if url not match
|
||||||
|
app.use(redirectServedPath(paths.publicUrlOrPath));
|
||||||
|
|
||||||
|
// This service worker file is effectively a 'no-op' that will reset any
|
||||||
|
// previous service worker registered for the same host:port combination.
|
||||||
|
// We do this in development to avoid hitting the production cache if
|
||||||
|
// it used the same host and port.
|
||||||
|
// https://github.com/facebook/create-react-app/issues/2272#issuecomment-302832432
|
||||||
|
app.use(noopServiceWorkerMiddleware(paths.publicUrlOrPath));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
14
docker/Dockerfile
Normal file
14
docker/Dockerfile
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
FROM nginx:stable-alpine
|
||||||
|
ARG version=0.0.0
|
||||||
|
ENV VERSION=${version}
|
||||||
|
# ENV INTERCEPT_POST=true
|
||||||
|
|
||||||
|
COPY pub /etc/nginx/html
|
||||||
|
COPY docker/nginx/nginx.conf /etc/nginx/nginx.conf
|
||||||
|
COPY docker/nginx/default.conf /etc/nginx/conf.d/default.conf
|
||||||
|
COPY docker/docker-entrypoint.sh /docker-entrypoint.d/40-dynamic-subpath.sh
|
||||||
|
RUN chmod +x /docker-entrypoint.d/40-dynamic-subpath.sh \
|
||||||
|
&& echo ${version} > /etc/nginx/html/VERSION
|
||||||
|
|
||||||
|
EXPOSE 80
|
||||||
|
CMD ["nginx", "-g", "daemon off;"]
|
||||||
25
docker/Dockerfile.build
Normal file
25
docker/Dockerfile.build
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# build environment
|
||||||
|
FROM node:16 as builder
|
||||||
|
WORKDIR /app
|
||||||
|
ENV PATH /app/node_modules/.bin:$PATH
|
||||||
|
COPY package.json ./
|
||||||
|
COPY package-lock.json ./
|
||||||
|
RUN npm install
|
||||||
|
COPY . ./
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# production environment
|
||||||
|
FROM nginx:stable-alpine
|
||||||
|
ARG version=0.0.0
|
||||||
|
ENV VERSION=${version}
|
||||||
|
# ENV INTERCEPT_POST=true
|
||||||
|
|
||||||
|
COPY --from=builder /app/dist /etc/nginx/html
|
||||||
|
COPY docker/nginx/nginx.conf /etc/nginx/nginx.conf
|
||||||
|
COPY docker/nginx/default.conf /etc/nginx/conf.d/default.conf
|
||||||
|
COPY docker/docker-entrypoint.sh /docker-entrypoint.d/40-dynamic-subpath.sh
|
||||||
|
RUN chmod +x /docker-entrypoint.d/40-dynamic-subpath.sh \
|
||||||
|
&& echo ${version} > /etc/nginx/html/VERSION
|
||||||
|
|
||||||
|
EXPOSE 80
|
||||||
|
CMD ["nginx", "-g", "daemon off;"]
|
||||||
19
docker/Dockerfile.subpath
Normal file
19
docker/Dockerfile.subpath
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# build environment
|
||||||
|
FROM node:14 as builder
|
||||||
|
WORKDIR /app
|
||||||
|
ENV PATH /app/node_modules/.bin:$PATH
|
||||||
|
ENV REACT_APP_BASE $BASE_PATH
|
||||||
|
ENV PUBLIC_URL $BASE_PATH/admin
|
||||||
|
COPY package.json ./
|
||||||
|
COPY package-lock.json ./
|
||||||
|
RUN npm install
|
||||||
|
COPY . ./
|
||||||
|
RUN REACT_APP_BASE=/changzhou PUBLIC_URL=/changzhou/admin GENERATE_SOURCEMAP=false node scripts/build.js
|
||||||
|
|
||||||
|
# production environment
|
||||||
|
FROM nginx:stable-alpine
|
||||||
|
COPY --from=builder /app/dist /etc/nginx/html
|
||||||
|
COPY nginx/nginx.conf /etc/nginx/nginx.conf
|
||||||
|
COPY nginx/default.conf /etc/nginx/conf.d/default.conf
|
||||||
|
EXPOSE 80
|
||||||
|
CMD ["nginx", "-g", "daemon off;"]
|
||||||
13
docker/docker-entrypoint.sh
Normal file
13
docker/docker-entrypoint.sh
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [[ "$APP_SUB_PATH" ]]; then
|
||||||
|
sed -i s@/admin/@$APP_SUB_PATH/admin/@g /etc/nginx/html/index.html
|
||||||
|
sed -i s@basePath:\"@basePath:\"$APP_SUB_PATH@g /etc/nginx/html/static/js/main*
|
||||||
|
sed -i s@\"/api/report-api/@\"${APP_SUB_PATH}/api/report-api/@g /etc/nginx/html/static/js/*
|
||||||
|
sed -i s@'/download@'$APP_SUB_PATH/download@g /etc/nginx/html/static/js/*
|
||||||
|
sed -i s@/admin/preview@$APP_SUB_PATH/admin/preview@g /etc/nginx/html/static/js/*
|
||||||
|
sed -i s@baseURL=\"/api\"@baseURL=\"$APP_SUB_PATH/api\"@g /etc/nginx/html/static/js/main*
|
||||||
|
sed -i s@"/admin/"@"$APP_SUB_PATH/admin/"@g /etc/nginx/html/static/css/*
|
||||||
|
fi
|
||||||
19
docker/nginx/default.conf
Normal file
19
docker/nginx/default.conf
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
server {
|
||||||
|
|
||||||
|
listen 80;
|
||||||
|
|
||||||
|
location ^~ /admin {
|
||||||
|
alias /etc/nginx/html;
|
||||||
|
try_files $uri $uri/index.html @admin;
|
||||||
|
}
|
||||||
|
|
||||||
|
location @admin {
|
||||||
|
rewrite ^.*$ /admin/index.html last;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_page 500 502 503 504 /50x.html;
|
||||||
|
|
||||||
|
location = /50x.html {
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
}
|
||||||
|
}
|
||||||
98
docker/nginx/nginx.conf
Normal file
98
docker/nginx/nginx.conf
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
# user www-data;
|
||||||
|
worker_processes 2;
|
||||||
|
pid /run/nginx.pid;
|
||||||
|
|
||||||
|
events {
|
||||||
|
worker_connections 1024;
|
||||||
|
# multi_accept on;
|
||||||
|
}
|
||||||
|
|
||||||
|
http {
|
||||||
|
|
||||||
|
##
|
||||||
|
# Basic Settings
|
||||||
|
##
|
||||||
|
|
||||||
|
sendfile on;
|
||||||
|
tcp_nopush on;
|
||||||
|
tcp_nodelay on;
|
||||||
|
keepalive_timeout 65;
|
||||||
|
types_hash_max_size 2048;
|
||||||
|
client_max_body_size 10m;
|
||||||
|
# server_tokens off;
|
||||||
|
|
||||||
|
# server_names_hash_bucket_size 64;
|
||||||
|
# server_name_in_redirect off;
|
||||||
|
|
||||||
|
include /etc/nginx/mime.types;
|
||||||
|
default_type application/octet-stream;
|
||||||
|
|
||||||
|
##
|
||||||
|
# Logging Settings
|
||||||
|
##
|
||||||
|
|
||||||
|
access_log /var/log/nginx/access.log;
|
||||||
|
error_log /var/log/nginx/error.log;
|
||||||
|
|
||||||
|
##
|
||||||
|
# Gzip Settings
|
||||||
|
##
|
||||||
|
|
||||||
|
gzip on;
|
||||||
|
gzip_disable "msie6";
|
||||||
|
|
||||||
|
gzip_vary on;
|
||||||
|
gzip_min_length 1000;
|
||||||
|
gzip_proxied expired no-cache no-store private auth;
|
||||||
|
gzip_comp_level 6;
|
||||||
|
gzip_buffers 16 8k;
|
||||||
|
gzip_http_version 1.1;
|
||||||
|
gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript application/x-ipynb+json;
|
||||||
|
|
||||||
|
##
|
||||||
|
# nginx-naxsi config
|
||||||
|
##
|
||||||
|
# Uncomment it if you installed nginx-naxsi
|
||||||
|
##
|
||||||
|
|
||||||
|
#include /etc/nginx/naxsi_core.rules;
|
||||||
|
|
||||||
|
##
|
||||||
|
# nginx-passenger config
|
||||||
|
##
|
||||||
|
# Uncomment it if you installed nginx-passenger
|
||||||
|
##
|
||||||
|
|
||||||
|
#passenger_root /usr;
|
||||||
|
#passenger_ruby /usr/bin/ruby;
|
||||||
|
|
||||||
|
##
|
||||||
|
# Virtual Host Configs
|
||||||
|
##
|
||||||
|
client_header_buffer_size 16k;
|
||||||
|
|
||||||
|
include /etc/nginx/conf.d/*.conf;
|
||||||
|
include /etc/nginx/sites-enabled/*;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#mail {
|
||||||
|
# # See sample authentication script at:
|
||||||
|
# # http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript
|
||||||
|
#
|
||||||
|
# # auth_http localhost/auth.php;
|
||||||
|
# # pop3_capabilities "TOP" "USER";
|
||||||
|
# # imap_capabilities "IMAP4rev1" "UIDPLUS";
|
||||||
|
#
|
||||||
|
# server {
|
||||||
|
# listen localhost:110;
|
||||||
|
# protocol pop3;
|
||||||
|
# proxy on;
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# server {
|
||||||
|
# listen localhost:143;
|
||||||
|
# protocol imap;
|
||||||
|
# proxy on;
|
||||||
|
# }
|
||||||
|
#}
|
||||||
6
mock/index.js
Normal file
6
mock/index.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
module.exports = {
|
||||||
|
'/api/login': {
|
||||||
|
status: 0,
|
||||||
|
msg: '登录成功',
|
||||||
|
},
|
||||||
|
};
|
||||||
31116
package-lock.json
generated
Normal file
31116
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
130
package.json
Normal file
130
package.json
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
{
|
||||||
|
"name": "olms-admin",
|
||||||
|
"version": "1.2.0",
|
||||||
|
"homepage": "admin",
|
||||||
|
"scripts": {
|
||||||
|
"start": "node scripts/start.js",
|
||||||
|
"build": "node scripts/build.js",
|
||||||
|
"build-sub": "REACT_APP_BASE=/tianmuhu PUBLIC_URL=/tianmuhu/admin GENERATE_SOURCEMAP=false node scripts/build.js",
|
||||||
|
"test": "node scripts/test.js",
|
||||||
|
"analyze": "webpack-bundle-analyzer --port 8080 dist/stats.json",
|
||||||
|
"lint": "prettier --config ./.prettierrc.yaml --write ."
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@fluentui/react": "^7.161.0",
|
||||||
|
"@rjsf/core": "^2.4.2",
|
||||||
|
"@rjsf/fluent-ui": "^2.4.2",
|
||||||
|
"@types/crypto-js": "^4.1.1",
|
||||||
|
"amis": "^6.8.0",
|
||||||
|
"amis-core": "^6.8.0",
|
||||||
|
"amis-ui": "^6.8.0",
|
||||||
|
"antd": "^4.18.6",
|
||||||
|
"axios": "^0.24.0",
|
||||||
|
"bootstrap": "^3.4.1",
|
||||||
|
"classnames": "^2.2.6",
|
||||||
|
"copy-to-clipboard": "3.3.2",
|
||||||
|
"crypto-js": "^4.0.0",
|
||||||
|
"date-fns": "^2.16.1",
|
||||||
|
"font-awesome": "^4.7.0",
|
||||||
|
"history": "^4.7.2",
|
||||||
|
"js-cookie": "^2.2.1",
|
||||||
|
"lodash": "^4.17.15",
|
||||||
|
"mammoth": "^1.4.21",
|
||||||
|
"mini-css-extract-plugin": "^2.6.0",
|
||||||
|
"mobx": "4.15.4",
|
||||||
|
"mobx-react": "6.1.8",
|
||||||
|
"mobx-state-tree": "^3.17.3",
|
||||||
|
"promise": "^8.1.0",
|
||||||
|
"promise-polyfill": "8.2.0",
|
||||||
|
"qs": "6.5.1",
|
||||||
|
"react": "^16.10.2",
|
||||||
|
"react-big-calendar": "^0.40.0",
|
||||||
|
"react-dom": "^16.10.2",
|
||||||
|
"react-perfect-scrollbar": "^1.5.8",
|
||||||
|
"react-router": "5.1.2",
|
||||||
|
"react-router-dom": "5.1.2",
|
||||||
|
"resolve": "^1.22.0",
|
||||||
|
"resolve-url-loader": "^5.0.0",
|
||||||
|
"vditor": "^3.10.7",
|
||||||
|
"viewerjs": "^1.10.1",
|
||||||
|
"xlsx": "^0.16.9"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/cli": "^7.17.6",
|
||||||
|
"@babel/core": "^7.17.9",
|
||||||
|
"@babel/plugin-proposal-decorators": "^7.17.9",
|
||||||
|
"@babel/preset-env": "^7.16.11",
|
||||||
|
"@babel/preset-react": "^7.16.7",
|
||||||
|
"@babel/preset-typescript": "^7.16.7",
|
||||||
|
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.5",
|
||||||
|
"@types/js-cookie": "^2.2.6",
|
||||||
|
"@types/lodash": "^4.14.123",
|
||||||
|
"@types/node": "^11.13.8",
|
||||||
|
"@types/qs": "^6.5.3",
|
||||||
|
"@types/react": "^16.8.4",
|
||||||
|
"@types/react-big-calendar": "^0.24.8",
|
||||||
|
"@types/react-dom": "^16.8.4",
|
||||||
|
"@types/react-router-dom": "^5.1.6",
|
||||||
|
"amis-editor": "^6.8.0",
|
||||||
|
"amis-editor-core": "^6.8.0",
|
||||||
|
"axios-mock-adapter": "1.16.0",
|
||||||
|
"babel-loader": "^8.2.4",
|
||||||
|
"bfj": "^7.0.2",
|
||||||
|
"case-sensitive-paths-webpack-plugin": "^2.4.0",
|
||||||
|
"clean-webpack-plugin": "^3.0.0",
|
||||||
|
"core-js": "^3.22.0",
|
||||||
|
"css-loader": "^3.4.2",
|
||||||
|
"css-minimizer-webpack-plugin": "^3.4.1",
|
||||||
|
"dotenv": "^16.0.0",
|
||||||
|
"dotenv-expand": "^8.0.3",
|
||||||
|
"file-loader": "^5.0.2",
|
||||||
|
"fs-walk": "0.0.2",
|
||||||
|
"html-minifier": "^4.0.0",
|
||||||
|
"html-webpack-plugin": "^5.5.0",
|
||||||
|
"http-proxy-middleware": "^2.0.4",
|
||||||
|
"mocker-api": "^1.11.2",
|
||||||
|
"pnp-webpack-plugin": "^1.7.0",
|
||||||
|
"postcss": "^8.4.12",
|
||||||
|
"postcss-custom-properties": "^12.1.7",
|
||||||
|
"postcss-flexbugs-fixes": "4.2.1",
|
||||||
|
"postcss-loader": "^4.3.0",
|
||||||
|
"postcss-normalize": "8.0.1",
|
||||||
|
"postcss-preset-env": "6.7.0",
|
||||||
|
"postcss-safe-parser": "5.0.2",
|
||||||
|
"prettier": "^2.6.2",
|
||||||
|
"react-dev-utils": "^12.0.1",
|
||||||
|
"react-error-overlay": "6.0.9",
|
||||||
|
"sass": "^1.45.2",
|
||||||
|
"sass-loader": "^8.0.2",
|
||||||
|
"speed-measure-webpack-plugin": "^1.5.0",
|
||||||
|
"style-loader": "^1.1.3",
|
||||||
|
"terser-webpack-plugin": "^5.3.1",
|
||||||
|
"ts-pnp": "^1.2.0",
|
||||||
|
"tslib": "^2.3.1",
|
||||||
|
"type-fest": "^2.12.1",
|
||||||
|
"typescript": "^4.4.4",
|
||||||
|
"url": "^0.11.0",
|
||||||
|
"url-loader": "^4.1.1",
|
||||||
|
"webpack": "^5.28.0",
|
||||||
|
"webpack-bundle-analyzer": "^4.5.0",
|
||||||
|
"webpack-cli": "^4.6.0",
|
||||||
|
"webpack-dev-server": "^4.8.1",
|
||||||
|
"webpack-manifest-plugin": "^5.0.0",
|
||||||
|
"workbox-webpack-plugin": "^6.5.3"
|
||||||
|
},
|
||||||
|
"overrides": {
|
||||||
|
"react-error-overlay": "6.0.9"
|
||||||
|
},
|
||||||
|
"browserslist": {
|
||||||
|
"production": [
|
||||||
|
">0.2%",
|
||||||
|
"not dead",
|
||||||
|
"not op_mini all"
|
||||||
|
],
|
||||||
|
"development": [
|
||||||
|
">0.2%",
|
||||||
|
"not dead",
|
||||||
|
"not op_mini all"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
17
postcss.config.js
Normal file
17
postcss.config.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
const postcssNormalize = require('postcss-normalize');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
plugins: () => [
|
||||||
|
require('postcss-flexbugs-fixes'),
|
||||||
|
require('postcss-preset-env')({
|
||||||
|
autoprefixer: {
|
||||||
|
flexbox: 'no-2009',
|
||||||
|
},
|
||||||
|
stage: 3,
|
||||||
|
}),
|
||||||
|
// Adds PostCSS Normalize as the reset css with default options,
|
||||||
|
// so that it honors browserslist config in package.json
|
||||||
|
// which in turn let's users customize the target behavior as per their needs.
|
||||||
|
postcssNormalize(),
|
||||||
|
],
|
||||||
|
};
|
||||||
BIN
public/favicon.ico
Normal file
BIN
public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.4 KiB |
38
public/index.html
Normal file
38
public/index.html
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<meta name="theme-color" content="#000000" />
|
||||||
|
<meta name="description" content="智医教学实践平台" />
|
||||||
|
<!--
|
||||||
|
manifest.json provides metadata used when your web app is installed on a
|
||||||
|
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||||
|
-->
|
||||||
|
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||||
|
<!--
|
||||||
|
Notice the use of %PUBLIC_URL% in the tags above.
|
||||||
|
It will be replaced with the URL of the `public` folder during the build.
|
||||||
|
Only files inside the `public` folder can be referenced from the HTML.
|
||||||
|
|
||||||
|
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||||
|
work correctly both with client-side routing and a non-root public URL.
|
||||||
|
Learn how to configure a non-root public URL by running `npm run build`.
|
||||||
|
-->
|
||||||
|
<title>智医教学实践平台</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
|
<div id="root" class="app-wrapper"></div>
|
||||||
|
<!--
|
||||||
|
This HTML file is a template.
|
||||||
|
If you open it directly in the browser, you will see an empty page.
|
||||||
|
|
||||||
|
You can add webfonts, meta tags, or analytics to this file.
|
||||||
|
The build step will place the bundled scripts into the <body> tag.
|
||||||
|
|
||||||
|
To begin the development, run `npm start` or `yarn start`.
|
||||||
|
To create a production bundle, use `npm run build` or `yarn build`.
|
||||||
|
--></body>
|
||||||
|
</html>
|
||||||
25
public/manifest.json
Normal file
25
public/manifest.json
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"short_name": "OLMS",
|
||||||
|
"name": "智医教学实践平台",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "favicon.ico",
|
||||||
|
"sizes": "64x64 32x32 24x24 16x16",
|
||||||
|
"type": "image/x-icon"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "logo192.png",
|
||||||
|
"type": "image/png",
|
||||||
|
"sizes": "192x192"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "logo512.png",
|
||||||
|
"type": "image/png",
|
||||||
|
"sizes": "512x512"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"start_url": ".",
|
||||||
|
"display": "standalone",
|
||||||
|
"theme_color": "#000000",
|
||||||
|
"background_color": "#ffffff"
|
||||||
|
}
|
||||||
3
public/robots.txt
Normal file
3
public/robots.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# https://www.robotstxt.org/robotstxt.html
|
||||||
|
User-agent: *
|
||||||
|
Disallow:
|
||||||
215
scripts/build.js
Normal file
215
scripts/build.js
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
// Do this as the first thing so that any code reading it knows the right env.
|
||||||
|
process.env.BABEL_ENV = 'production';
|
||||||
|
process.env.NODE_ENV = 'production';
|
||||||
|
|
||||||
|
// Makes the script crash on unhandled rejections instead of silently
|
||||||
|
// ignoring them. In the future, promise rejections that are not handled will
|
||||||
|
// terminate the Node.js process with a non-zero exit code.
|
||||||
|
process.on('unhandledRejection', (err) => {
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Ensure environment variables are read.
|
||||||
|
require('../config/env');
|
||||||
|
|
||||||
|
const path = require('path');
|
||||||
|
const chalk = require('react-dev-utils/chalk');
|
||||||
|
const fs = require('fs-extra');
|
||||||
|
const bfj = require('bfj');
|
||||||
|
const webpack = require('webpack');
|
||||||
|
const configFactory = require('../config/webpack.config');
|
||||||
|
const paths = require('../config/paths');
|
||||||
|
const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
|
||||||
|
const formatWebpackMessages = require('react-dev-utils/formatWebpackMessages');
|
||||||
|
const printHostingInstructions = require('react-dev-utils/printHostingInstructions');
|
||||||
|
const FileSizeReporter = require('react-dev-utils/FileSizeReporter');
|
||||||
|
const printBuildError = require('react-dev-utils/printBuildError');
|
||||||
|
|
||||||
|
const measureFileSizesBeforeBuild =
|
||||||
|
FileSizeReporter.measureFileSizesBeforeBuild;
|
||||||
|
const printFileSizesAfterBuild = FileSizeReporter.printFileSizesAfterBuild;
|
||||||
|
const useYarn = fs.existsSync(paths.yarnLockFile);
|
||||||
|
|
||||||
|
// These sizes are pretty large. We'll warn for bundles exceeding them.
|
||||||
|
const WARN_AFTER_BUNDLE_GZIP_SIZE = 512 * 1024;
|
||||||
|
const WARN_AFTER_CHUNK_GZIP_SIZE = 1024 * 1024;
|
||||||
|
|
||||||
|
const isInteractive = process.stdout.isTTY;
|
||||||
|
|
||||||
|
// Warn and crash if required files are missing
|
||||||
|
if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const argv = process.argv.slice(2);
|
||||||
|
const writeStatsJson = argv.indexOf('--stats') !== -1;
|
||||||
|
|
||||||
|
// Generate configuration
|
||||||
|
const config = configFactory('production');
|
||||||
|
|
||||||
|
// We require that you explicitly set browsers and do not fall back to
|
||||||
|
// browserslist defaults.
|
||||||
|
const { checkBrowsers } = require('react-dev-utils/browsersHelper');
|
||||||
|
checkBrowsers(paths.appPath, isInteractive)
|
||||||
|
.then(() => {
|
||||||
|
// First, read the current file sizes in build directory.
|
||||||
|
// This lets us display how much they changed later.
|
||||||
|
return measureFileSizesBeforeBuild(paths.appBuild);
|
||||||
|
})
|
||||||
|
.then((previousFileSizes) => {
|
||||||
|
// Remove all content but keep the directory so that
|
||||||
|
// if you're in it, you don't end up in Trash
|
||||||
|
fs.emptyDirSync(paths.appBuild);
|
||||||
|
// Merge with the public folder
|
||||||
|
copyPublicFolder();
|
||||||
|
// Start the webpack build
|
||||||
|
return build(previousFileSizes);
|
||||||
|
})
|
||||||
|
.then(
|
||||||
|
({ stats, previousFileSizes, warnings }) => {
|
||||||
|
if (warnings.length) {
|
||||||
|
console.log(chalk.yellow('Compiled with warnings.\n'));
|
||||||
|
console.log(warnings.join('\n\n'));
|
||||||
|
console.log(
|
||||||
|
'\nSearch for the ' +
|
||||||
|
chalk.underline(chalk.yellow('keywords')) +
|
||||||
|
' to learn more about each warning.'
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
'To ignore, add ' +
|
||||||
|
chalk.cyan('// eslint-disable-next-line') +
|
||||||
|
' to the line before.\n'
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
console.log(chalk.green('Compiled successfully.\n'));
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('File sizes after gzip:\n');
|
||||||
|
printFileSizesAfterBuild(
|
||||||
|
stats,
|
||||||
|
previousFileSizes,
|
||||||
|
paths.appBuild,
|
||||||
|
WARN_AFTER_BUNDLE_GZIP_SIZE,
|
||||||
|
WARN_AFTER_CHUNK_GZIP_SIZE
|
||||||
|
);
|
||||||
|
console.log();
|
||||||
|
|
||||||
|
const appPackage = require(paths.appPackageJson);
|
||||||
|
const publicUrl = paths.publicUrlOrPath;
|
||||||
|
const publicPath = config.output.publicPath;
|
||||||
|
const buildFolder = path.relative(process.cwd(), paths.appBuild);
|
||||||
|
printHostingInstructions(
|
||||||
|
appPackage,
|
||||||
|
publicUrl,
|
||||||
|
publicPath,
|
||||||
|
buildFolder,
|
||||||
|
useYarn
|
||||||
|
);
|
||||||
|
},
|
||||||
|
(err) => {
|
||||||
|
const tscCompileOnError =
|
||||||
|
process.env.TSC_COMPILE_ON_ERROR === 'true';
|
||||||
|
if (tscCompileOnError) {
|
||||||
|
console.log(
|
||||||
|
chalk.yellow(
|
||||||
|
'Compiled with the following type errors (you may want to check these before deploying your app):\n'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
printBuildError(err);
|
||||||
|
} else {
|
||||||
|
console.log(chalk.red('Failed to compile.\n'));
|
||||||
|
printBuildError(err);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.catch((err) => {
|
||||||
|
if (err && err.message) {
|
||||||
|
console.log(err.message);
|
||||||
|
}
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create the production build and print the deployment instructions.
|
||||||
|
function build(previousFileSizes) {
|
||||||
|
console.log('Creating an optimized production build...');
|
||||||
|
|
||||||
|
const compiler = webpack(config);
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
compiler.run((err, stats) => {
|
||||||
|
let messages;
|
||||||
|
if (err) {
|
||||||
|
if (!err.message) {
|
||||||
|
return reject(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
let errMessage = err.message;
|
||||||
|
|
||||||
|
// Add additional information for postcss errors
|
||||||
|
if (Object.prototype.hasOwnProperty.call(err, 'postcssNode')) {
|
||||||
|
errMessage +=
|
||||||
|
'\nCompileError: Begins at CSS selector ' +
|
||||||
|
err['postcssNode'].selector;
|
||||||
|
}
|
||||||
|
|
||||||
|
messages = formatWebpackMessages({
|
||||||
|
errors: [errMessage],
|
||||||
|
warnings: [],
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
messages = formatWebpackMessages(
|
||||||
|
stats.toJson({ all: false, warnings: true, errors: true })
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (messages.errors.length) {
|
||||||
|
// Only keep the first error. Others are often indicative
|
||||||
|
// of the same problem, but confuse the reader with noise.
|
||||||
|
if (messages.errors.length > 1) {
|
||||||
|
messages.errors.length = 1;
|
||||||
|
}
|
||||||
|
return reject(new Error(messages.errors.join('\n\n')));
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
process.env.CI &&
|
||||||
|
(typeof process.env.CI !== 'string' ||
|
||||||
|
process.env.CI.toLowerCase() !== 'false') &&
|
||||||
|
messages.warnings.length
|
||||||
|
) {
|
||||||
|
console.log(
|
||||||
|
chalk.yellow(
|
||||||
|
'\nTreating warnings as errors because process.env.CI = true.\n' +
|
||||||
|
'Most CI servers set it automatically.\n'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return reject(new Error(messages.warnings.join('\n\n')));
|
||||||
|
}
|
||||||
|
|
||||||
|
const resolveArgs = {
|
||||||
|
stats,
|
||||||
|
previousFileSizes,
|
||||||
|
warnings: messages.warnings,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (writeStatsJson) {
|
||||||
|
return bfj
|
||||||
|
.write(
|
||||||
|
paths.appBuild + '/bundle-stats.json',
|
||||||
|
stats.toJson()
|
||||||
|
)
|
||||||
|
.then(() => resolve(resolveArgs))
|
||||||
|
.catch((error) => reject(new Error(error)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolve(resolveArgs);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function copyPublicFolder() {
|
||||||
|
fs.copySync(paths.appPublic, paths.appBuild, {
|
||||||
|
dereference: true,
|
||||||
|
filter: (file) => file !== paths.appHtml,
|
||||||
|
});
|
||||||
|
}
|
||||||
171
scripts/start.js
Normal file
171
scripts/start.js
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
// Do this as the first thing so that any code reading it knows the right env.
|
||||||
|
process.env.BABEL_ENV = 'development';
|
||||||
|
process.env.NODE_ENV = 'development';
|
||||||
|
|
||||||
|
// Makes the script crash on unhandled rejections instead of silently
|
||||||
|
// ignoring them. In the future, promise rejections that are not handled will
|
||||||
|
// terminate the Node.js process with a non-zero exit code.
|
||||||
|
process.on('unhandledRejection', (err) => {
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Ensure environment variables are read.
|
||||||
|
require('../config/env');
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const chalk = require('react-dev-utils/chalk');
|
||||||
|
const webpack = require('webpack');
|
||||||
|
const WebpackDevServer = require('webpack-dev-server');
|
||||||
|
const clearConsole = require('react-dev-utils/clearConsole');
|
||||||
|
const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
|
||||||
|
const {
|
||||||
|
choosePort,
|
||||||
|
createCompiler,
|
||||||
|
prepareProxy,
|
||||||
|
prepareUrls,
|
||||||
|
} = require('react-dev-utils/WebpackDevServerUtils');
|
||||||
|
const openBrowser = require('react-dev-utils/openBrowser');
|
||||||
|
const semver = require('semver');
|
||||||
|
const paths = require('../config/paths');
|
||||||
|
const configFactory = require('../config/webpack.config');
|
||||||
|
const createDevServerConfig = require('../config/webpackDevServer.config');
|
||||||
|
const getClientEnvironment = require('../config/env');
|
||||||
|
const react = require(require.resolve('react', { paths: [paths.appPath] }));
|
||||||
|
|
||||||
|
const env = getClientEnvironment(paths.publicUrlOrPath.slice(0, -1));
|
||||||
|
const useYarn = fs.existsSync(paths.yarnLockFile);
|
||||||
|
const isInteractive = process.stdout.isTTY;
|
||||||
|
|
||||||
|
// Warn and crash if required files are missing
|
||||||
|
if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tools like Cloud9 rely on this.
|
||||||
|
const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000;
|
||||||
|
const HOST = process.env.HOST || '0.0.0.0';
|
||||||
|
|
||||||
|
if (process.env.HOST) {
|
||||||
|
console.log(
|
||||||
|
chalk.cyan(
|
||||||
|
`Attempting to bind to HOST environment variable: ${chalk.yellow(
|
||||||
|
chalk.bold(process.env.HOST)
|
||||||
|
)}`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
`If this was unintentional, check that you haven't mistakenly set it in your shell.`
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
`Learn more here: ${chalk.yellow('https://cra.link/advanced-config')}`
|
||||||
|
);
|
||||||
|
console.log();
|
||||||
|
}
|
||||||
|
|
||||||
|
// We require that you explicitly set browsers and do not fall back to
|
||||||
|
// browserslist defaults.
|
||||||
|
const { checkBrowsers } = require('react-dev-utils/browsersHelper');
|
||||||
|
checkBrowsers(paths.appPath, isInteractive)
|
||||||
|
.then(() => {
|
||||||
|
// We attempt to use the default port but if it is busy, we offer the user to
|
||||||
|
// run on a different port. `choosePort()` Promise resolves to the next free port.
|
||||||
|
return choosePort(HOST, DEFAULT_PORT);
|
||||||
|
})
|
||||||
|
.then((port) => {
|
||||||
|
if (port == null) {
|
||||||
|
// We have not found a port.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = configFactory("development");
|
||||||
|
const protocol = process.env.HTTPS === "true" ? "https" : "http";
|
||||||
|
const appName = require(paths.appPackageJson).name;
|
||||||
|
|
||||||
|
const useTypeScript = fs.existsSync(paths.appTsConfig);
|
||||||
|
const tscCompileOnError = process.env.TSC_COMPILE_ON_ERROR === "true";
|
||||||
|
const urls = prepareUrls(
|
||||||
|
protocol,
|
||||||
|
HOST,
|
||||||
|
port,
|
||||||
|
paths.publicUrlOrPath.slice(0, -1)
|
||||||
|
);
|
||||||
|
const devSocket = {
|
||||||
|
warnings: (warnings) =>
|
||||||
|
devServer.sockWrite(devServer.sockets, "warnings", warnings),
|
||||||
|
errors: (errors) =>
|
||||||
|
devServer.sockWrite(devServer.sockets, "errors", errors),
|
||||||
|
};
|
||||||
|
// Create a webpack compiler that is configured with custom messages.
|
||||||
|
const compiler = createCompiler({
|
||||||
|
appName,
|
||||||
|
config,
|
||||||
|
devSocket,
|
||||||
|
urls,
|
||||||
|
useYarn,
|
||||||
|
useTypeScript,
|
||||||
|
tscCompileOnError,
|
||||||
|
webpack,
|
||||||
|
});
|
||||||
|
// Load proxy config
|
||||||
|
const proxySetting = require(paths.appPackageJson).proxy;
|
||||||
|
const proxyConfig = prepareProxy(
|
||||||
|
proxySetting,
|
||||||
|
paths.appPublic,
|
||||||
|
paths.publicUrlOrPath
|
||||||
|
);
|
||||||
|
// Serve webpack assets generated by the compiler over a web server.
|
||||||
|
const serverConfig = createDevServerConfig(
|
||||||
|
proxyConfig,
|
||||||
|
urls.lanUrlForConfig
|
||||||
|
);
|
||||||
|
serverConfig.host = HOST;
|
||||||
|
serverConfig.port = port;
|
||||||
|
serverConfig.setupExitSignals = true;
|
||||||
|
|
||||||
|
const devServer = new WebpackDevServer(serverConfig, compiler);
|
||||||
|
|
||||||
|
// Launch WebpackDevServer.
|
||||||
|
devServer.startCallback((err) => {
|
||||||
|
if (err) {
|
||||||
|
return console.log(err);
|
||||||
|
}
|
||||||
|
if (isInteractive) {
|
||||||
|
clearConsole();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (env.raw.FAST_REFRESH && semver.lt(react.version, "16.10.0")) {
|
||||||
|
console.log(
|
||||||
|
chalk.yellow(
|
||||||
|
`Fast Refresh requires React 16.10 or higher. You are using React ${react.version}.`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(chalk.cyan("Starting the development server...\n"));
|
||||||
|
openBrowser(urls.localUrlForBrowser);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
['SIGINT', 'SIGTERM'].forEach(function (sig) {
|
||||||
|
process.on(sig, function () {
|
||||||
|
devServer.close();
|
||||||
|
process.exit();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (process.env.CI !== 'true') {
|
||||||
|
// Gracefully exit when stdin ends
|
||||||
|
process.stdin.on('end', function () {
|
||||||
|
devServer.close();
|
||||||
|
process.exit();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
if (err && err.message) {
|
||||||
|
console.log(err.message);
|
||||||
|
}
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
51
scripts/test.js
Normal file
51
scripts/test.js
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
// Do this as the first thing so that any code reading it knows the right env.
|
||||||
|
process.env.BABEL_ENV = 'test';
|
||||||
|
process.env.NODE_ENV = 'test';
|
||||||
|
process.env.PUBLIC_URL = '';
|
||||||
|
|
||||||
|
// Makes the script crash on unhandled rejections instead of silently
|
||||||
|
// ignoring them. In the future, promise rejections that are not handled will
|
||||||
|
// terminate the Node.js process with a non-zero exit code.
|
||||||
|
process.on('unhandledRejection', (err) => {
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Ensure environment variables are read.
|
||||||
|
require('../config/env');
|
||||||
|
|
||||||
|
const jest = require('jest');
|
||||||
|
const execSync = require('child_process').execSync;
|
||||||
|
let argv = process.argv.slice(2);
|
||||||
|
|
||||||
|
function isInGitRepository() {
|
||||||
|
try {
|
||||||
|
execSync('git rev-parse --is-inside-work-tree', { stdio: 'ignore' });
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isInMercurialRepository() {
|
||||||
|
try {
|
||||||
|
execSync('hg --cwd . root', { stdio: 'ignore' });
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Watch unless on CI or explicitly running all tests
|
||||||
|
if (
|
||||||
|
!process.env.CI &&
|
||||||
|
argv.indexOf('--watchAll') === -1 &&
|
||||||
|
argv.indexOf('--watchAll=false') === -1
|
||||||
|
) {
|
||||||
|
// https://github.com/facebook/create-react-app/issues/5210
|
||||||
|
const hasSourceControl = isInGitRepository() || isInMercurialRepository();
|
||||||
|
argv.push(hasSourceControl ? '--watch' : '--watchAll');
|
||||||
|
}
|
||||||
|
|
||||||
|
jest.run(argv);
|
||||||
290
src/App.css
Normal file
290
src/App.css
Normal file
@@ -0,0 +1,290 @@
|
|||||||
|
.cxd-Layout-content {
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-page .cxd-Page-body {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.cxd-DropDown-menu {
|
||||||
|
min-width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cxd-Tree {
|
||||||
|
height: 84vh;
|
||||||
|
max-height: inherit!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cxd-ListControl-item:hover:active:hover,
|
||||||
|
.cxd-ListControl-item.is-active:hover {
|
||||||
|
background-color: var(--ListControl-item-onActive-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.plan-list .cxd-ListControl-items {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rbc-allday-cell {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rbc-month-row {
|
||||||
|
min-height: 128px;
|
||||||
|
border-color: rgba(0, 0, 0, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.copy-list {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.copy-list .cxd-GroupedSelection-item {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* https://github.com/rjsf-team/react-jsonschema-form/issues/2188 */
|
||||||
|
/* .rjsf .field-undefined> :nth-child(1) {
|
||||||
|
display: none;
|
||||||
|
} */
|
||||||
|
|
||||||
|
.rjsf [for='root']:first-child + #root__description {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.rjsf .css-42:last-child {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.rjsf .field-array span:last-child {
|
||||||
|
float: none !important;
|
||||||
|
}
|
||||||
|
.rjsf fieldset {
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
.rjsf .btn-add::after {
|
||||||
|
content: '添加';
|
||||||
|
}
|
||||||
|
.rjsf.array-item-move-up::after {
|
||||||
|
content: '上移';
|
||||||
|
}
|
||||||
|
.rjsf.array-item-move-down::after {
|
||||||
|
content: '下移';
|
||||||
|
}
|
||||||
|
.rjsf.array-item-remove::after {
|
||||||
|
content: '删除';
|
||||||
|
}
|
||||||
|
.rjsf .form-group {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
.rjsf .form-group label {
|
||||||
|
display: inline-block;
|
||||||
|
max-width: 100%;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rjsf .form-control {
|
||||||
|
max-width: 100%;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
background: var(--Form-input-bg);
|
||||||
|
border: var(--Form-input-borderWidth) solid var(--Form-input-borderColor);
|
||||||
|
border-radius: var(--Form-input-borderRadius);
|
||||||
|
line-height: var(--Form-input-lineHeight);
|
||||||
|
padding: var(--Form-input-paddingY) var(--Form-input-paddingX);
|
||||||
|
font-size: var(--Form-input-fontSize);
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview table {
|
||||||
|
width: 100%;
|
||||||
|
border: 1px solid #000000;
|
||||||
|
border-collapse: separate;
|
||||||
|
border-left: 0;
|
||||||
|
-webkit-border-radius: 4px;
|
||||||
|
-moz-border-radius: 4px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: transparent;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview table thead:first-child tr:first-child > th:first-child,
|
||||||
|
.preview table tbody:first-child tr:first-child > td:first-child {
|
||||||
|
-webkit-border-top-left-radius: 4px;
|
||||||
|
border-top-left-radius: 4px;
|
||||||
|
-moz-border-radius-topleft: 4px;
|
||||||
|
}
|
||||||
|
.preview table thead th {
|
||||||
|
vertical-align: bottom;
|
||||||
|
}
|
||||||
|
.preview table th,
|
||||||
|
.preview table td {
|
||||||
|
padding: 4px 8px !important;
|
||||||
|
line-height: 14px;
|
||||||
|
text-align: left;
|
||||||
|
vertical-align: top;
|
||||||
|
border-left: 1px solid #000000;
|
||||||
|
border-top: 1px solid #000000;
|
||||||
|
}
|
||||||
|
.preview table th {
|
||||||
|
padding: 4px 8px;
|
||||||
|
line-height: 20px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
/*custom*/
|
||||||
|
.cxd-Select-popover {
|
||||||
|
z-index: 1500;
|
||||||
|
}
|
||||||
|
.tox {
|
||||||
|
z-index: 1400 !important;
|
||||||
|
}
|
||||||
|
.amis-scope .cxd-PopOver {
|
||||||
|
z-index: 1400 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#print-preview .cxd-Table-fixedTop {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.common-padding {
|
||||||
|
padding: 0px 0 4px 10px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 部门管理 */
|
||||||
|
.partment-grid .cxd-Grid-col--md3 {
|
||||||
|
padding-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.partment-grid .cxd-Grid-col--md9 {
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.partment-height {
|
||||||
|
height: 84vh;
|
||||||
|
max-height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 报告模板 */
|
||||||
|
.rpt-tp-height {
|
||||||
|
height: 81vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 教学计划 */
|
||||||
|
.experiment {
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: 0;
|
||||||
|
width: 230px;
|
||||||
|
height: 20px;
|
||||||
|
vertical-align: middle;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.experiment:hover {
|
||||||
|
display: inline-block;
|
||||||
|
width: auto;
|
||||||
|
height: 20px;
|
||||||
|
min-width: 230px;
|
||||||
|
vertical-align: middle;
|
||||||
|
white-space: none;
|
||||||
|
overflow: unset;
|
||||||
|
text-overflow: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
.class {
|
||||||
|
display: inline-block;
|
||||||
|
width: 140px;
|
||||||
|
height: 20px;
|
||||||
|
vertical-align: middle;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.class:hover {
|
||||||
|
display: inline-block;
|
||||||
|
width: auto;
|
||||||
|
height: 20px;
|
||||||
|
min-width: 140px;
|
||||||
|
vertical-align: middle;
|
||||||
|
white-space: none;
|
||||||
|
overflow: unset;
|
||||||
|
text-overflow: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
.course_select .cxd-Select-menu {
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trash {
|
||||||
|
padding: 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrapper {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrapper .is-disabled {
|
||||||
|
background: grey;
|
||||||
|
color: white !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab .cxd-Tabs-content {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table {
|
||||||
|
width: auto;
|
||||||
|
min-width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-purple {
|
||||||
|
color: rgb(175, 167, 175);
|
||||||
|
}
|
||||||
|
|
||||||
|
.question img {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
.question-option p {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.question .cxd-Button {
|
||||||
|
display: inline-block;
|
||||||
|
width: 480px;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-align: left;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-permission-tree {
|
||||||
|
max-height: none;
|
||||||
|
}
|
||||||
|
.evaluation-height {
|
||||||
|
height: 75vh;
|
||||||
|
max-height: 75vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cxd-Modal {
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery .cxd-Modal-content {
|
||||||
|
border: 0;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery .cxd-Modal-content.in,
|
||||||
|
.gallery .cxd-Modal-content.out {
|
||||||
|
animation-fill-mode: none;
|
||||||
|
}
|
||||||
|
.device-frame {
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
.root-41 {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
171
src/App.tsx
Normal file
171
src/App.tsx
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
import { alert, confirm, toast } from 'amis-ui';
|
||||||
|
import axios from 'axios';
|
||||||
|
import copy from 'copy-to-clipboard';
|
||||||
|
import _, { isString } from 'lodash';
|
||||||
|
import { Provider } from 'mobx-react';
|
||||||
|
import * as React from 'react';
|
||||||
|
import RootRoute from './routes';
|
||||||
|
import { MainStore } from './stores';
|
||||||
|
import './utils/icons';
|
||||||
|
import { request } from './utils/requestInterceptor';
|
||||||
|
import { resRequest } from './utils/resRequestInterceptor';
|
||||||
|
|
||||||
|
import './renderer/AttScoreRule';
|
||||||
|
import './renderer/Calendar';
|
||||||
|
import './renderer/CourseList';
|
||||||
|
import './renderer/DataPreview';
|
||||||
|
import './renderer/DataTrial';
|
||||||
|
import './renderer/ProjectScoreItem';
|
||||||
|
import './renderer/Scheduler';
|
||||||
|
import './renderer/TimeslotPicker';
|
||||||
|
import './renderer/TimeslotPicker/Copy';
|
||||||
|
import './renderer/Workload';
|
||||||
|
// import './renderer/DataPreview1';
|
||||||
|
import './renderer/BatchGroup';
|
||||||
|
import './renderer/CustomImageUpload';
|
||||||
|
import './renderer/CustomRichtext';
|
||||||
|
import './renderer/DataSet';
|
||||||
|
import './renderer/DataSetPicker';
|
||||||
|
import './renderer/DownloadReport';
|
||||||
|
import './renderer/DownloadReportSchedule';
|
||||||
|
import './renderer/ExamImport';
|
||||||
|
import './renderer/ExamPaperRule';
|
||||||
|
import './renderer/ExcelImport';
|
||||||
|
import './renderer/ExcelImportDeduction';
|
||||||
|
import './renderer/ExcelImportGroup';
|
||||||
|
import './renderer/ExcelImportSchedule';
|
||||||
|
import './renderer/ExcelImportStudent';
|
||||||
|
import './renderer/ExcelImportStudentOrg';
|
||||||
|
import './renderer/Group';
|
||||||
|
import './renderer/ImageGallery';
|
||||||
|
import './renderer/Option';
|
||||||
|
import './renderer/TextbookSubmit';
|
||||||
|
import './renderer/Vditor';
|
||||||
|
|
||||||
|
// css
|
||||||
|
import 'font-awesome/css/font-awesome.css';
|
||||||
|
// import 'amis/lib/themes/antd.css';
|
||||||
|
import 'amis-ui/lib/themes/cxd.css';
|
||||||
|
// import './scss/style.scss'
|
||||||
|
// import 'amis/sdk/iconfont.css'
|
||||||
|
import 'amis/lib/helper.css';
|
||||||
|
import './App.css';
|
||||||
|
|
||||||
|
export default function (): JSX.Element {
|
||||||
|
console.log(React);
|
||||||
|
const store = ((window as any).store = MainStore.create(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
fetcher: ({ url, method, data, config, headers }: any) => {
|
||||||
|
config = config || {};
|
||||||
|
config.headers = config.headers || {};
|
||||||
|
config.withCredentials = true;
|
||||||
|
config.baseURL = '/api';
|
||||||
|
// config.baseURL = '/changzhou/api';
|
||||||
|
// config.baseURL = prefix ? `${prefix}/api` : '/api';
|
||||||
|
|
||||||
|
if (config.cancelExecutor) {
|
||||||
|
config.cancelToken = new axios.CancelToken(config.cancelExecutor);
|
||||||
|
}
|
||||||
|
|
||||||
|
config.headers = headers || {};
|
||||||
|
config.method = method;
|
||||||
|
|
||||||
|
if (method === 'get' && data) {
|
||||||
|
config.params = data;
|
||||||
|
} else if (data && data instanceof FormData) {
|
||||||
|
// config.headers = config.headers || {};
|
||||||
|
// config.headers['Content-Type'] = 'multipart/form-data';
|
||||||
|
} else if (
|
||||||
|
data &&
|
||||||
|
typeof data !== 'string' &&
|
||||||
|
!(data instanceof Blob) &&
|
||||||
|
!(data instanceof ArrayBuffer)
|
||||||
|
) {
|
||||||
|
data = JSON.stringify(data);
|
||||||
|
// config.headers = config.headers || {};
|
||||||
|
config.headers['Content-Type'] = 'application/json';
|
||||||
|
}
|
||||||
|
|
||||||
|
let match = url.match(/\[(.*?)\]/);
|
||||||
|
while (match) {
|
||||||
|
url = url.replace(match[0], `.${match[1]}`);
|
||||||
|
match = url.match(/\[(.*?)\]/);
|
||||||
|
}
|
||||||
|
|
||||||
|
let apiPrefix = url.match(/^[^/]*\//);
|
||||||
|
if (
|
||||||
|
config.headers.post2rest !== false &&
|
||||||
|
(config.method === 'put' ||
|
||||||
|
config.method === 'patch' ||
|
||||||
|
config.method === 'delete')
|
||||||
|
) {
|
||||||
|
url = _.replace(
|
||||||
|
url,
|
||||||
|
/^[^/]*\//,
|
||||||
|
`${apiPrefix}post2rest/${config.method}/`
|
||||||
|
);
|
||||||
|
config.method = 'post';
|
||||||
|
}
|
||||||
|
|
||||||
|
let token = window.sessionStorage.getItem('authenticated');
|
||||||
|
if (token && url !== '/api/rpc/login') {
|
||||||
|
config.headers['Authorization'] = `Bearer ${token}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
data && (config.data = data);
|
||||||
|
config.url = url;
|
||||||
|
|
||||||
|
return request(config);
|
||||||
|
},
|
||||||
|
resFetcher: ({ url, method, data, config, headers }): any => {
|
||||||
|
config = config || {};
|
||||||
|
config.headers = config.headers || {};
|
||||||
|
config.withCredentials = true;
|
||||||
|
config.baseURL = '';
|
||||||
|
|
||||||
|
if (config.cancelExecutor) {
|
||||||
|
config.cancelToken = new axios.CancelToken(config.cancelExecutor);
|
||||||
|
}
|
||||||
|
|
||||||
|
config.headers = headers || {};
|
||||||
|
config.method = method;
|
||||||
|
|
||||||
|
let auth = window.sessionStorage.getItem('auth');
|
||||||
|
|
||||||
|
if (auth) {
|
||||||
|
config.headers['X-Auth'] = auth;
|
||||||
|
}
|
||||||
|
|
||||||
|
data && (config.data = data);
|
||||||
|
config.url = url;
|
||||||
|
|
||||||
|
return resRequest(config);
|
||||||
|
},
|
||||||
|
isCancel: (e: any) => axios.isCancel(e),
|
||||||
|
notify: (type: 'success' | 'error' | 'info', msg: string) => {
|
||||||
|
if ((isString(msg) && msg) || msg?.message) {
|
||||||
|
toast[type]
|
||||||
|
? toast[type](msg, type === 'error' ? '系统错误' : '系统消息')
|
||||||
|
: console.warn('[Notify]', type, msg);
|
||||||
|
console.log('[notify]', type, msg);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
alert,
|
||||||
|
confirm,
|
||||||
|
copy: (contents: string, options: any = {}) => {
|
||||||
|
const ret = copy(contents, options);
|
||||||
|
ret &&
|
||||||
|
(!options || options.shutup !== true) &&
|
||||||
|
toast.info('内容已拷贝到剪切板');
|
||||||
|
return ret;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Provider store={store}>
|
||||||
|
<RootRoute store={store} />
|
||||||
|
</Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
61
src/components/AMisRenderer.tsx
Normal file
61
src/components/AMisRenderer.tsx
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import { render as renderSchema } from 'amis';
|
||||||
|
import { IMainStore } from '@/stores';
|
||||||
|
import { inject, observer } from 'mobx-react';
|
||||||
|
import { withRouter } from 'react-router';
|
||||||
|
import { Action } from 'amis/lib/types';
|
||||||
|
import renderOptions from '@/utils/renderOptions';
|
||||||
|
|
||||||
|
interface RendererProps {
|
||||||
|
schema?: any;
|
||||||
|
[propName: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
@inject('store')
|
||||||
|
// @ts-ignore
|
||||||
|
@withRouter
|
||||||
|
@observer
|
||||||
|
export default class AMisRenderer extends React.Component<RendererProps, any> {
|
||||||
|
env: any = null;
|
||||||
|
|
||||||
|
handleAction = (e: any, action: Action) => {
|
||||||
|
this.env.alert(`没有识别的动作:${JSON.stringify(action)}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(props: RendererProps) {
|
||||||
|
super(props);
|
||||||
|
const store = props.store as IMainStore;
|
||||||
|
const history = props.history;
|
||||||
|
|
||||||
|
this.env = renderOptions(store, history);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { schema, store, onAction, ...rest } = this.props;
|
||||||
|
return renderSchema(
|
||||||
|
schema,
|
||||||
|
{
|
||||||
|
data: {
|
||||||
|
user: store.user,
|
||||||
|
currentSemester: store.currentSemester?.id,
|
||||||
|
semester: store.currentSemester,
|
||||||
|
semesterSelect: store.currentSemester?.id,
|
||||||
|
periods: store.periods,
|
||||||
|
basePath: store.basePath,
|
||||||
|
},
|
||||||
|
onAction: (e: any, action: any) => {
|
||||||
|
console.log(action)
|
||||||
|
if (!action || action.actionType === 'url') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (action.actionType === 'logout') {
|
||||||
|
store.logout();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
theme: store && store.theme,
|
||||||
|
...rest,
|
||||||
|
},
|
||||||
|
this.env
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
215
src/components/UserInfo.tsx
Normal file
215
src/components/UserInfo.tsx
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import AMisRenderer from './AMisRenderer';
|
||||||
|
|
||||||
|
interface UserInfoProps {
|
||||||
|
user: any;
|
||||||
|
}
|
||||||
|
interface UserInfoState {
|
||||||
|
open?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class UserInfo extends React.Component<
|
||||||
|
UserInfoProps,
|
||||||
|
UserInfoState
|
||||||
|
> {
|
||||||
|
constructor(props: UserInfoProps) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
open: false,
|
||||||
|
};
|
||||||
|
this.open = this.open.bind(this);
|
||||||
|
this.close = this.close.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
static defaultProps = {};
|
||||||
|
open() {
|
||||||
|
this.setState({
|
||||||
|
open: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
close() {
|
||||||
|
this.setState({
|
||||||
|
open: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
handleClickOutside() {
|
||||||
|
this.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const user = this.props.user;
|
||||||
|
|
||||||
|
const schema = {
|
||||||
|
type: 'page',
|
||||||
|
className: 'user-page',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '工作台',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'url',
|
||||||
|
args: {
|
||||||
|
url: '/hub/login?jwt=$user.token',
|
||||||
|
params: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
id: 'u:05fc5e4362bc',
|
||||||
|
themeCss: {
|
||||||
|
className: {
|
||||||
|
'padding-and-margin:default': {
|
||||||
|
marginRight: '5px',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// type: 'button',
|
||||||
|
// label: '探索',
|
||||||
|
// onEvent: {
|
||||||
|
// click: {
|
||||||
|
// actions: [
|
||||||
|
// {
|
||||||
|
// ignoreError: false,
|
||||||
|
// actionType: 'url',
|
||||||
|
// args: {
|
||||||
|
// url: '/explore?token=$user.token',
|
||||||
|
// params: {},
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// id: 'u:05fc5e4362bd',
|
||||||
|
// themeCss: {
|
||||||
|
// className: {
|
||||||
|
// 'padding-and-margin:default': {
|
||||||
|
// marginRight: '5px',
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '资源管理',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'url',
|
||||||
|
args: {
|
||||||
|
url: '/res',
|
||||||
|
params: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
id: 'u:05fc5e4362bc',
|
||||||
|
themeCss: {
|
||||||
|
className: {
|
||||||
|
'padding-and-margin:default': {
|
||||||
|
marginRight: '5px',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'dropdown-button',
|
||||||
|
label: user.name,
|
||||||
|
align: 'right',
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
icon: 'fa fa-cog',
|
||||||
|
label: '系统信息 ',
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
closeOnEsc: true,
|
||||||
|
title: '系统信息',
|
||||||
|
size: 'sm',
|
||||||
|
type: 'dialog',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'tpl',
|
||||||
|
tpl: '<p>智医教学实践平台</p>\n<p>OLMS II</p>',
|
||||||
|
inline: false,
|
||||||
|
id: 'u:369cb33ce9d0',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
showCloseButton: true,
|
||||||
|
showErrorMsg: true,
|
||||||
|
showLoading: true,
|
||||||
|
id: 'u:289af4d19c37',
|
||||||
|
actions: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
icon: 'fa fa-key',
|
||||||
|
label: '修改密码 ',
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
closeOnEsc: true,
|
||||||
|
title: '修改登录密码',
|
||||||
|
size: 'sm',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
api: {
|
||||||
|
url: `rest/rpc/change_password`,
|
||||||
|
method: 'post',
|
||||||
|
data: {
|
||||||
|
password: '${password}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
messages: {
|
||||||
|
saveSuccess: '[密码修改成功] 请使用新密码重新登录',
|
||||||
|
saveFailed: '密码修改失败',
|
||||||
|
},
|
||||||
|
// redirect: '/login',
|
||||||
|
mode: 'horizontal',
|
||||||
|
horizontal: {
|
||||||
|
left: 'col-sm-3',
|
||||||
|
right: 'col-sm-9',
|
||||||
|
},
|
||||||
|
controls: [
|
||||||
|
{
|
||||||
|
type: 'password',
|
||||||
|
name: 'password',
|
||||||
|
required: true,
|
||||||
|
label: '新密码',
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// type: 'password',
|
||||||
|
// name: 'confirmPassword',
|
||||||
|
// required: true,
|
||||||
|
// label: '重复密码',
|
||||||
|
// },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'logout',
|
||||||
|
level: 'link',
|
||||||
|
icon: 'fa fa-reply',
|
||||||
|
label: '退出登录 ',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
return <AMisRenderer schema={schema} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
13
src/index.css
Normal file
13
src/index.css
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto',
|
||||||
|
'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans',
|
||||||
|
'Helvetica Neue', sans-serif;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||||
|
monospace;
|
||||||
|
}
|
||||||
29
src/index.tsx
Normal file
29
src/index.tsx
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import { render } from 'react-dom';
|
||||||
|
import App from './App';
|
||||||
|
import 'react-perfect-scrollbar/dist/css/styles.css';
|
||||||
|
import './index.css';
|
||||||
|
|
||||||
|
export function bootstrap(mountTo: HTMLElement) {
|
||||||
|
render(<App />, mountTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
(self as any).MonacoEnvironment = {
|
||||||
|
getWorkerUrl: function (moduleId: any, label: string) {
|
||||||
|
if (label === 'json') {
|
||||||
|
return '/json.worker.bundle.js';
|
||||||
|
}
|
||||||
|
if (label === 'css') {
|
||||||
|
return '/css.worker.bundle.js';
|
||||||
|
}
|
||||||
|
if (label === 'html') {
|
||||||
|
return '/html.worker.bundle.js';
|
||||||
|
}
|
||||||
|
if (label === 'typescript' || label === 'javascript') {
|
||||||
|
return '/ts.worker.bundle.js';
|
||||||
|
}
|
||||||
|
return '/editor.worker.bundle.js';
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
bootstrap(document.getElementById('root')!);
|
||||||
16
src/pages/404.tsx
Normal file
16
src/pages/404.tsx
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { NotFound } from 'amis';
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<NotFound
|
||||||
|
links={
|
||||||
|
<Link to="/" className="list-group-item">
|
||||||
|
<i className="fa fa-chevron-right text-muted" />
|
||||||
|
<i className="fa fa-fw fa-mail-forward m-r-xs" />
|
||||||
|
去首页
|
||||||
|
</Link>
|
||||||
|
}
|
||||||
|
footerText={''}
|
||||||
|
/>
|
||||||
|
);
|
||||||
116
src/pages/Editor.tsx
Normal file
116
src/pages/Editor.tsx
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
import React, { useEffect } from 'react';
|
||||||
|
import { Editor, ShortcutKey } from 'amis-editor';
|
||||||
|
import { inject, observer } from 'mobx-react';
|
||||||
|
import { RouteComponentProps } from 'react-router-dom';
|
||||||
|
import 'amis/lib/themes/cxd.css';
|
||||||
|
import 'amis/lib/helper.css';
|
||||||
|
import 'amis/sdk/iconfont.css';
|
||||||
|
import 'amis-editor-core/lib/style.css';
|
||||||
|
// import 'amis/lib/themes/default.css';
|
||||||
|
import '../scss/editor.scss';
|
||||||
|
|
||||||
|
import { IMainStore } from '../stores';
|
||||||
|
import loadPageByPath from '../utils/loadPageByPath';
|
||||||
|
import renderOptions from '../utils/renderOptions';
|
||||||
|
|
||||||
|
export default inject('store')(
|
||||||
|
observer(function ({
|
||||||
|
store,
|
||||||
|
history,
|
||||||
|
match,
|
||||||
|
}: { store: IMainStore } & RouteComponentProps<{ id: string }>) {
|
||||||
|
const pageId: number = parseInt(match.params.id, 10);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
(async () => {
|
||||||
|
let nav: any = store.flat_navigations.find((x: any) => x.id === pageId);
|
||||||
|
let pagePath = nav ? nav.schema_path : '';
|
||||||
|
loadPageByPath(pagePath).then((page: any) => {
|
||||||
|
store.updateSchema(page.schema);
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
}, [pageId]);
|
||||||
|
|
||||||
|
function save() {
|
||||||
|
console.log(store.schema);
|
||||||
|
store.copy(JSON.stringify(store.schema));
|
||||||
|
}
|
||||||
|
|
||||||
|
function exit() {
|
||||||
|
history.goBack();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="Editor-Demo">
|
||||||
|
<div className="Editor-header">
|
||||||
|
<div className="Editor-title">可视化编辑器</div>
|
||||||
|
<div className="Editor-view-mode-group-container">
|
||||||
|
<div className="Editor-view-mode-group">
|
||||||
|
<div
|
||||||
|
className={`Editor-view-mode-btn editor-header-icon ${
|
||||||
|
!store.isMobile ? 'is-active' : ''
|
||||||
|
}`}
|
||||||
|
onClick={() => {
|
||||||
|
store.setIsMobile(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
PC
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={`Editor-view-mode-btn editor-header-icon ${
|
||||||
|
store.isMobile ? 'is-active' : ''
|
||||||
|
}`}
|
||||||
|
onClick={() => {
|
||||||
|
store.setIsMobile(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
H5
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="Editor-header-actions">
|
||||||
|
<ShortcutKey />
|
||||||
|
|
||||||
|
<div
|
||||||
|
className={`header-action-btn m-1 ${
|
||||||
|
store.preview ? 'primary' : ''
|
||||||
|
}`}
|
||||||
|
onClick={() => {
|
||||||
|
store.setPreview(!store.preview);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{store.preview ? '编辑' : '预览'}
|
||||||
|
</div>
|
||||||
|
{!store.preview && (
|
||||||
|
<>
|
||||||
|
<div className={`header-action-btn`} onClick={save}>
|
||||||
|
保存
|
||||||
|
</div>
|
||||||
|
<div className={`header-action-btn exit-btn`} onClick={exit}>
|
||||||
|
退出
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="Editor-inner">
|
||||||
|
<Editor
|
||||||
|
theme={store.theme}
|
||||||
|
preview={store.preview}
|
||||||
|
isMobile={store.isMobile}
|
||||||
|
value={store.schema}
|
||||||
|
onChange={(value: any) => store.updateSchema(value)}
|
||||||
|
onPreview={() => {
|
||||||
|
store.setPreview(true);
|
||||||
|
}}
|
||||||
|
onSave={save}
|
||||||
|
className="is-fixed"
|
||||||
|
showCustomRenderersPanel={true}
|
||||||
|
amisEnv={renderOptions(store, history)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
);
|
||||||
113
src/pages/Login.tsx
Normal file
113
src/pages/Login.tsx
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
import { MD5 } from 'crypto-js';
|
||||||
|
import { inject, observer } from 'mobx-react';
|
||||||
|
import React from 'react';
|
||||||
|
import { RouteComponentProps, withRouter } from 'react-router-dom';
|
||||||
|
import AMisRenderer from '../components/AMisRenderer';
|
||||||
|
import { IMainStore } from '../stores/index';
|
||||||
|
|
||||||
|
interface LoginProps extends RouteComponentProps<any> {
|
||||||
|
store: IMainStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
const schema = {
|
||||||
|
type: 'page',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'wrapper',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'plain',
|
||||||
|
tpl: '用户登录',
|
||||||
|
inline: false,
|
||||||
|
className: 'block m-t-xxl m-b-xl text-center text-2x text-info',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
submitText: '登录',
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'rest/rpc/login',
|
||||||
|
data: {
|
||||||
|
code: '${username}',
|
||||||
|
password: '${password}',
|
||||||
|
},
|
||||||
|
requestAdaptor: (api: any) => {
|
||||||
|
api.body.password = MD5(api.body.password).toString();
|
||||||
|
return api;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wrapWithPanel: false,
|
||||||
|
canAccessSuperData: false,
|
||||||
|
messages: {
|
||||||
|
saveSuccess: '',
|
||||||
|
},
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
label: '',
|
||||||
|
type: 'input-text',
|
||||||
|
name: 'username',
|
||||||
|
required: true,
|
||||||
|
placeholder: '用户名',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-password',
|
||||||
|
label: '',
|
||||||
|
name: 'password',
|
||||||
|
placeholder: '密码',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'submit',
|
||||||
|
label: '登录',
|
||||||
|
size: 'lg',
|
||||||
|
block: true,
|
||||||
|
level: 'primary',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
className: 'bg-white w-xxl Modal-content',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
className: 'bg-white h-full',
|
||||||
|
};
|
||||||
|
|
||||||
|
@inject('store')
|
||||||
|
// @ts-ignore
|
||||||
|
@withRouter
|
||||||
|
@observer
|
||||||
|
export default class LoginRoute extends React.Component<LoginProps> {
|
||||||
|
handleFormSaved = (value: any) => {
|
||||||
|
const store = this.props.store;
|
||||||
|
const history = this.props.history;
|
||||||
|
let user = null;
|
||||||
|
|
||||||
|
if (value.items) {
|
||||||
|
user = value.items[0].login;
|
||||||
|
} else {
|
||||||
|
user = value;
|
||||||
|
}
|
||||||
|
store.notify('登录成功!');
|
||||||
|
store.user.login(user);
|
||||||
|
history.push('/');
|
||||||
|
store
|
||||||
|
.resFetcher({
|
||||||
|
url: '/res/api/login',
|
||||||
|
method: 'post',
|
||||||
|
data: {
|
||||||
|
username: '',
|
||||||
|
password: '',
|
||||||
|
recaptcha: '',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then((res: any) => {
|
||||||
|
console.log(res);
|
||||||
|
document.cookie = `auth=${res.data.data}; Path=/; SameSite=Strict;"`;
|
||||||
|
sessionStorage.setItem('auth', res.data.data);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return <AMisRenderer onFinished={this.handleFormSaved} schema={schema} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
124
src/pages/Preview.tsx
Normal file
124
src/pages/Preview.tsx
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { inject, observer } from 'mobx-react';
|
||||||
|
import { RouteComponentProps, withRouter } from 'react-router-dom';
|
||||||
|
import { IMainStore } from '../stores/index';
|
||||||
|
import AMisRenderer from '../components/AMisRenderer';
|
||||||
|
|
||||||
|
interface LoginProps extends RouteComponentProps<any> {
|
||||||
|
store: IMainStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
const schema = {
|
||||||
|
type: 'page',
|
||||||
|
bodyClassName: 'w-4/5 m-auto',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'plain',
|
||||||
|
tpl: '实验开放教学登记表',
|
||||||
|
inline: false,
|
||||||
|
className: 'text-center text-2x font-bold',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'plain',
|
||||||
|
tpl: '实验名称:${project}',
|
||||||
|
inline: false,
|
||||||
|
className: 'm-t-xs',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'plain',
|
||||||
|
tpl: '课堂编号:${id} 指导教师:${teacher} 地点:${location} \n 实验时间:${date} ${start_time}',
|
||||||
|
inline: false,
|
||||||
|
className: 'm-sm',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'plain',
|
||||||
|
tpl: '备注:登记表请妥善保存,学期结束时必须交到实验室存档,不能遗失!',
|
||||||
|
inline: false,
|
||||||
|
className: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'crud',
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/user2projects?select=id,student:users!user2project_student_id_fkey(id,code,name,user_orgs(orgs(name)))&schedule_id=eq.${id}&schedule_status=in.(elected,stopped)&order=id.asc',
|
||||||
|
adaptor:
|
||||||
|
'payload.data.items = payload.data.items.map((item, index) => {\r\n return {\r\n ...item,\r\n order_number: index + 1\r\n }\r\n});\r\nreturn payload;',
|
||||||
|
},
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'order_number',
|
||||||
|
label: '序号',
|
||||||
|
type: 'text',
|
||||||
|
placeholder: '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'student.code',
|
||||||
|
label: '学号',
|
||||||
|
type: 'text',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '姓名',
|
||||||
|
name: 'student.name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'student.user_orgs[0].orgs.name',
|
||||||
|
label: '班级',
|
||||||
|
type: 'text',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '考勤',
|
||||||
|
name: 'att',
|
||||||
|
placeholder: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '预习',
|
||||||
|
name: 'prepare',
|
||||||
|
placeholder: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '操作',
|
||||||
|
name: 'op',
|
||||||
|
placeholder: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '报告',
|
||||||
|
name: 'report',
|
||||||
|
placeholder: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '备注',
|
||||||
|
name: 'beizhu',
|
||||||
|
placeholder: '',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
columnsTogglable: false,
|
||||||
|
affixHeader: false,
|
||||||
|
showHeader: true,
|
||||||
|
showFooter: true,
|
||||||
|
messages: {},
|
||||||
|
className: 'm-t-sm preview',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'tpl',
|
||||||
|
tpl: '<p>教师签字: </p>',
|
||||||
|
inline: false,
|
||||||
|
className: 'text-right',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
@inject('store')
|
||||||
|
// @ts-ignore
|
||||||
|
@withRouter
|
||||||
|
@observer
|
||||||
|
export default class LoginRoute extends React.Component<LoginProps> {
|
||||||
|
render() {
|
||||||
|
return <AMisRenderer schema={schema} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
41
src/pages/Schema.tsx
Normal file
41
src/pages/Schema.tsx
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { inject, observer } from 'mobx-react';
|
||||||
|
import { RouteComponentProps, useParams } from 'react-router-dom';
|
||||||
|
import { IMainStore } from '../stores/index';
|
||||||
|
import AMisRenderer from '../components/AMisRenderer';
|
||||||
|
import loadPageByPath from '../utils/loadPageByPath';
|
||||||
|
|
||||||
|
export default inject('store')(
|
||||||
|
observer(function ({
|
||||||
|
store,
|
||||||
|
}: { store: IMainStore } & RouteComponentProps<{
|
||||||
|
id: string;
|
||||||
|
}>) {
|
||||||
|
let { centre_id, id } = useParams<any>();
|
||||||
|
const [schema, setSchema] = useState({
|
||||||
|
type: 'page',
|
||||||
|
body: {
|
||||||
|
type: 'spinner',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setSchema({
|
||||||
|
type: 'page',
|
||||||
|
body: {
|
||||||
|
type: 'spinner',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
let nav: any = store.flat_navigations
|
||||||
|
.filter((x: any) => x.path !== null)
|
||||||
|
.find((x: any) => x.id.toString() === id);
|
||||||
|
let pagePath = nav ? nav.schema_path : '';
|
||||||
|
loadPageByPath(pagePath).then((page: any) => {
|
||||||
|
setSchema(page.schema);
|
||||||
|
});
|
||||||
|
}, [id]);
|
||||||
|
|
||||||
|
// TODO: schema中的api有时没自动加载
|
||||||
|
return <AMisRenderer schema={schema} centre_id={centre_id} />;
|
||||||
|
})
|
||||||
|
);
|
||||||
35
src/pages/Student.tsx
Normal file
35
src/pages/Student.tsx
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { RouteComponentProps } from 'react-router-dom';
|
||||||
|
import { inject, observer } from 'mobx-react';
|
||||||
|
import AMisRenderer from '../components/AMisRenderer';
|
||||||
|
import { IMainStore } from '../stores';
|
||||||
|
|
||||||
|
export default inject('store')(
|
||||||
|
observer(function ({
|
||||||
|
page,
|
||||||
|
store,
|
||||||
|
location,
|
||||||
|
history,
|
||||||
|
match,
|
||||||
|
}: { page: number } & { store: IMainStore } & RouteComponentProps<{
|
||||||
|
id: string;
|
||||||
|
}>) {
|
||||||
|
const schema = {
|
||||||
|
type: 'page',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'tpl',
|
||||||
|
tpl: '请使用微信选课',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
aside: [],
|
||||||
|
messages: {},
|
||||||
|
// "initApi": {
|
||||||
|
// "method": "get",
|
||||||
|
// "url": "/api/user2schedules"
|
||||||
|
// }
|
||||||
|
};
|
||||||
|
|
||||||
|
return <AMisRenderer schema={schema} />;
|
||||||
|
})
|
||||||
|
);
|
||||||
9
src/pages/admin/Dashboard.tsx
Normal file
9
src/pages/admin/Dashboard.tsx
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import schema2component from '@/utils/schema2component';
|
||||||
|
|
||||||
|
const schema = {
|
||||||
|
type: 'page',
|
||||||
|
title: 'Dashboard',
|
||||||
|
body: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
export default schema2component(schema);
|
||||||
346
src/pages/admin/index.tsx
Normal file
346
src/pages/admin/index.tsx
Normal file
@@ -0,0 +1,346 @@
|
|||||||
|
import RouterGuard from '@/routes/RouterGuard';
|
||||||
|
import { IMainStore } from '@/stores';
|
||||||
|
import { AsideNav, Button, Layout, toast } from 'amis';
|
||||||
|
import { inject, observer } from 'mobx-react';
|
||||||
|
import * as React from 'react';
|
||||||
|
import {
|
||||||
|
Link,
|
||||||
|
Redirect,
|
||||||
|
Route,
|
||||||
|
RouteComponentProps,
|
||||||
|
Switch,
|
||||||
|
matchPath,
|
||||||
|
} from 'react-router-dom';
|
||||||
|
import UserInfo from '../../components/UserInfo';
|
||||||
|
import SchemaRoute from '../Schema';
|
||||||
|
import Student from '../Student';
|
||||||
|
import AMisRenderer from '@/components/AMisRenderer';
|
||||||
|
|
||||||
|
type NavItem = {
|
||||||
|
label: string;
|
||||||
|
children?: Array<NavItem>;
|
||||||
|
icon?: string;
|
||||||
|
path?: string;
|
||||||
|
component?: React.ReactType;
|
||||||
|
getComponent?: () => Promise<React.ReactType>;
|
||||||
|
};
|
||||||
|
let PATH_PREFIX = '';
|
||||||
|
|
||||||
|
function isActive(link: any, location: any) {
|
||||||
|
const ret = matchPath(location.pathname, {
|
||||||
|
path: link ? link.replace(/\?.*$/, '') : '',
|
||||||
|
exact: true,
|
||||||
|
strict: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
return !!ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AdminProps extends RouteComponentProps<any> {
|
||||||
|
store: IMainStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
@inject('store')
|
||||||
|
@observer
|
||||||
|
export default class Admin extends React.Component<AdminProps, any> {
|
||||||
|
state = {
|
||||||
|
pathname: '',
|
||||||
|
hasLoadMenu: false,
|
||||||
|
navigations: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
logout = () => {
|
||||||
|
const store = this.props.store;
|
||||||
|
store.user.logout();
|
||||||
|
const history = this.props.history;
|
||||||
|
history.replace(`/login`);
|
||||||
|
};
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
const store = this.props.store;
|
||||||
|
const history = this.props.history;
|
||||||
|
console.log('componentDidMount, store.user:', store.user);
|
||||||
|
if (!store.user.isAuthenticated) {
|
||||||
|
// toast['error']('用户未登陆,请先登陆!', '消息');
|
||||||
|
history.replace(`/login`);
|
||||||
|
}
|
||||||
|
this.refreshMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshMenu = () => {
|
||||||
|
const store = this.props.store;
|
||||||
|
let pathname = this.props.location.pathname;
|
||||||
|
console.log('location:', pathname);
|
||||||
|
console.log('store.user:', store.user);
|
||||||
|
if (
|
||||||
|
pathname !== 'login' &&
|
||||||
|
!this.state.hasLoadMenu &&
|
||||||
|
store.user.isAuthenticated
|
||||||
|
) {
|
||||||
|
store.updateCentres();
|
||||||
|
store.updateSemesters();
|
||||||
|
store.updatePeriods();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
renderHeader() {
|
||||||
|
const store = this.props.store;
|
||||||
|
const theme = 'cxd';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className={`${theme}-Layout-brandBar`}>
|
||||||
|
<button
|
||||||
|
onClick={store.toggleOffScreen}
|
||||||
|
className="pull-right visible-xs"
|
||||||
|
>
|
||||||
|
<i className="glyphicon glyphicon-align-justify"></i>
|
||||||
|
</button>
|
||||||
|
<div className={`${theme}-Layout-brand`}>
|
||||||
|
<i className="fa "></i>
|
||||||
|
<span className="hidden-folded">{store.name}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={`${theme}-Layout-headerBar`}
|
||||||
|
style={{ justifyContent: 'space-between' }}
|
||||||
|
>
|
||||||
|
<div className="nav navbar-nav hidden-xs">
|
||||||
|
<Button
|
||||||
|
level="link"
|
||||||
|
className="no-shadow navbar-btn"
|
||||||
|
onClick={store.toggleAsideFolded}
|
||||||
|
tooltip="展开或收起侧边栏"
|
||||||
|
placement="bottom"
|
||||||
|
iconOnly
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
className={store.asideFolded ? 'fa fa-indent' : 'fa fa-dedent'}
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={()=>{
|
||||||
|
window.open('/doc')
|
||||||
|
}}
|
||||||
|
>帮助</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="hidden-xs">
|
||||||
|
<UserInfo user={store.user} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderCentreAside(
|
||||||
|
prefix: string,
|
||||||
|
items: Array<NavItem>,
|
||||||
|
centre_id: number
|
||||||
|
): Array<NavItem> {
|
||||||
|
if (!items) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return items.map((item: any) => {
|
||||||
|
if (item.children && item.children.length > 0) {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
children: this.renderCentreAside(prefix, item.children, centre_id),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// let centreSubPath = item.path && item.path.replace('centre/:id/', '');
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
path: `${prefix}/${item.id}?centre_id=${centre_id}`,
|
||||||
|
children: undefined,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
renderAside() {
|
||||||
|
const location = this.props.location;
|
||||||
|
const store = this.props.store;
|
||||||
|
let navigations = store.navigations.filter(
|
||||||
|
(item: any) => item.label !== '教学中心'
|
||||||
|
);
|
||||||
|
let centre_navigations = store.navigations.filter(
|
||||||
|
(item: any) => item.label === '教学中心'
|
||||||
|
);
|
||||||
|
let dynamic_navigations: Array<NavItem> = [];
|
||||||
|
this.props.store.centres?.forEach((item: any) => {
|
||||||
|
let centre_path = `centre/${item.id}`;
|
||||||
|
dynamic_navigations.push({
|
||||||
|
label: item.name,
|
||||||
|
icon: 'fa fa-institution',
|
||||||
|
// path: centre_path,
|
||||||
|
children: centre_navigations[0]
|
||||||
|
? this.renderCentreAside(
|
||||||
|
centre_path,
|
||||||
|
centre_navigations[0].children,
|
||||||
|
item.id
|
||||||
|
)
|
||||||
|
: [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AsideNav
|
||||||
|
key={store.asideFolded ? 'folded-aside' : 'aside'}
|
||||||
|
navigations={[{ children: navigations.concat(dynamic_navigations) }]}
|
||||||
|
renderLink={({ link, toggleExpand, classnames: cx, depth }: any) => {
|
||||||
|
if (link.hidden) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let children = [];
|
||||||
|
|
||||||
|
if (link.children && link.children.length > 0) {
|
||||||
|
children.push(
|
||||||
|
<span
|
||||||
|
key="expand-toggle"
|
||||||
|
className={cx('AsideNav-itemArrow')}
|
||||||
|
onClick={(e) => toggleExpand(link, e)}
|
||||||
|
></span>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
if (
|
||||||
|
process.env.NODE_ENV === 'development' &&
|
||||||
|
store.user.role === 'dev'
|
||||||
|
) {
|
||||||
|
children.push(
|
||||||
|
<i
|
||||||
|
key="edit"
|
||||||
|
data-tooltip="编辑"
|
||||||
|
data-position="bottom"
|
||||||
|
className={'navbtn fa fa-pencil'}
|
||||||
|
onClick={(e: React.MouseEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
this.props.history.push(`/edit/${link.page}`);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
link.badge &&
|
||||||
|
children.push(
|
||||||
|
<b
|
||||||
|
key="badge"
|
||||||
|
className={cx(
|
||||||
|
`AsideNav-itemBadge`,
|
||||||
|
link.badgeClassName || 'bg-info'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{link.badge}
|
||||||
|
</b>
|
||||||
|
);
|
||||||
|
|
||||||
|
if (link.icon) {
|
||||||
|
children.push(
|
||||||
|
<i key="icon" className={cx(`AsideNav-itemIcon`, link.icon)} />
|
||||||
|
);
|
||||||
|
} else if (store.asideFolded && depth === 1) {
|
||||||
|
children.push(
|
||||||
|
<i
|
||||||
|
key="icon"
|
||||||
|
className={cx(
|
||||||
|
`AsideNav-itemIcon`,
|
||||||
|
link.children ? 'fa fa-folder' : 'fa fa-info'
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
children.push(
|
||||||
|
<span key="label" className={cx('AsideNav-itemLabel')}>
|
||||||
|
{link.label}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
|
||||||
|
return link.schema_path ? (
|
||||||
|
link.active ? (
|
||||||
|
<a>{children}</a>
|
||||||
|
) : (
|
||||||
|
<Link to={`/page/${link.path}`}>{children}</Link>
|
||||||
|
)
|
||||||
|
) : (
|
||||||
|
<a
|
||||||
|
onClick={
|
||||||
|
link.onClick
|
||||||
|
? link.onClick
|
||||||
|
: link.children
|
||||||
|
? () => toggleExpand(link)
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
// renderSubLinks={({link,renderLink, depth}:any) =>{
|
||||||
|
// return (link.children && link.children.length ? (
|
||||||
|
// <ul className={'AsideNav-subList'}>
|
||||||
|
// {link.label ? (
|
||||||
|
// <li key="subHeader" className={'AsideNav-subHeader'}>
|
||||||
|
// <a>{link.label}</a>
|
||||||
|
// </li>
|
||||||
|
// ) : null}
|
||||||
|
// {link.children.map((link:any, key:any) =>
|
||||||
|
// renderLink(link, key, {}, depth + 1)
|
||||||
|
// )}
|
||||||
|
// </ul>
|
||||||
|
// ) : link.label && depth === 1 ? (
|
||||||
|
// <div className={'AsideNav-tooltip'}>{link.label}</div>
|
||||||
|
// ) : null)
|
||||||
|
// }}
|
||||||
|
isActive={(link: any) =>
|
||||||
|
isActive(
|
||||||
|
link.path && link.path[0] === '/'
|
||||||
|
? link.path
|
||||||
|
: `${PATH_PREFIX}/page/${link.path}`,
|
||||||
|
location
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const store = this.props.store;
|
||||||
|
let pathname = this.props.location.pathname;
|
||||||
|
console.log('location:', pathname);
|
||||||
|
if (pathname === 'login') {
|
||||||
|
return (
|
||||||
|
<Switch>
|
||||||
|
<RouterGuard />
|
||||||
|
<Redirect to={`/404`} />
|
||||||
|
</Switch>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Layout
|
||||||
|
theme="cxd"
|
||||||
|
aside={this.renderAside()}
|
||||||
|
header={this.renderHeader()}
|
||||||
|
folded={store.asideFolded}
|
||||||
|
offScreen={store.offScreen}
|
||||||
|
>
|
||||||
|
<Switch>
|
||||||
|
<Redirect to={`/${store.defaultNav}`} from={`/`} exact />
|
||||||
|
|
||||||
|
<Route
|
||||||
|
path="/page/centre/:centre_id/:id"
|
||||||
|
component={SchemaRoute}
|
||||||
|
/>
|
||||||
|
<Route path="/page/:id" component={SchemaRoute} />
|
||||||
|
<RouterGuard />
|
||||||
|
<Redirect to={`/404`} />
|
||||||
|
</Switch>
|
||||||
|
</Layout>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
66
src/pages/schema/centre/att/ercode.schema.ts
Normal file
66
src/pages/schema/centre/att/ercode.schema.ts
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
const schema = {
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '软件下载',
|
||||||
|
size: 'md',
|
||||||
|
level: 'primary',
|
||||||
|
block: false,
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
args: {
|
||||||
|
url: 'https://www.platosoft.org/download/ATT.zip',
|
||||||
|
},
|
||||||
|
actionType: 'url',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
weight: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '使用说明',
|
||||||
|
actionType: 'url',
|
||||||
|
size: 'md',
|
||||||
|
level: 'primary',
|
||||||
|
className: 'm-l',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
args: {
|
||||||
|
url: 'https://www.platosoft.org/doc/olms/manual/admin/att_qr.html',
|
||||||
|
},
|
||||||
|
actionType: 'url',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
weight: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'formula',
|
||||||
|
name: 'api_url',
|
||||||
|
formula: 'data.api_url=location.origin + this.basePath + "/api"',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'property',
|
||||||
|
title: '配置参数',
|
||||||
|
items: [
|
||||||
|
{ label: '接口地址', content: '$api_url', span: 1 },
|
||||||
|
{ label: '本地秘钥', content: 'olms', span: 1 },
|
||||||
|
],
|
||||||
|
column: 1,
|
||||||
|
mode: 'table',
|
||||||
|
className: 'w-xxl m-t',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
title: '二维码考勤',
|
||||||
|
type: 'page',
|
||||||
|
messages: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
export { schema };
|
||||||
28
src/pages/schema/centre/att/face.schema.ts
Normal file
28
src/pages/schema/centre/att/face.schema.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
const schema = {
|
||||||
|
body: [{ type: 'html', html: '<h1>人脸考勤使用说明</h1>' }],
|
||||||
|
type: 'page',
|
||||||
|
title: '人脸考勤使用说明',
|
||||||
|
toolbar: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '下载客户端',
|
||||||
|
level: 'success',
|
||||||
|
blank: true,
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
args: {
|
||||||
|
url: '/download/faceApp.zip',
|
||||||
|
},
|
||||||
|
actionType: 'url',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
weight: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export { schema };
|
||||||
461
src/pages/schema/centre/att/index.schema.ts
Normal file
461
src/pages/schema/centre/att/index.schema.ts
Normal file
@@ -0,0 +1,461 @@
|
|||||||
|
const schema = {
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
className: '',
|
||||||
|
name: 'filter',
|
||||||
|
title: '表单',
|
||||||
|
wrapWithPanel: false,
|
||||||
|
reload:
|
||||||
|
'adopt?organization_id=eq.$centre_id&project_id=$project_id&teacher_id=$teacher_id&location_id=$location_id&date=$date&class_list=$class_list&no_tch=$no_tch',
|
||||||
|
submitOnInit: true,
|
||||||
|
submitOnChange: true,
|
||||||
|
initApi: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/users?role=eq.teacher&id=eq.${user.id}&order=code',
|
||||||
|
adaptor:
|
||||||
|
"if (payload.data.items.length !== 0) {\r\n return {\r\n teacher_id: 'eq.'.concat(payload.data.items[0].id)\r\n }\r\n} else {\r\n return {}\r\n}",
|
||||||
|
},
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'group',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
name: 'project_id',
|
||||||
|
label: '实验',
|
||||||
|
mode: 'inline',
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/projects?organization_id=eq.$centre_id&semester_id=eq.$currentSemester&order=code',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: payload.data.items.map(item => {\r\n return {\r\n label: item.name,\r\n value: "eq.".concat(item.id)\r\n }\r\n })\r\n}',
|
||||||
|
},
|
||||||
|
size: 'md',
|
||||||
|
checkAll: false,
|
||||||
|
clearable: true,
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'group',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'input-date-range',
|
||||||
|
name: 'date',
|
||||||
|
mode: 'inline',
|
||||||
|
label: '日期',
|
||||||
|
clearable: true,
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
value: '',
|
||||||
|
format: 'YYYY-MM-DD',
|
||||||
|
ranges:
|
||||||
|
'yesterday,today,7daysago,prevweek,thismonth,prevmonth,prevquarter',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
label: '地点',
|
||||||
|
name: 'location_id',
|
||||||
|
mode: 'inline',
|
||||||
|
checkAll: false,
|
||||||
|
clearable: true,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/locations?organization_id=eq.$centre_id&order=code',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: payload.data.items.map(item => {\r\n return {\r\n label: item.name,\r\n value: "eq.".concat(item.id)\r\n }\r\n })\r\n}',
|
||||||
|
},
|
||||||
|
size: 'md',
|
||||||
|
className: 'm-l-sm',
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
name: 'teacher_id',
|
||||||
|
label: '教师',
|
||||||
|
checkAll: false,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/users?role=eq.teacher&order=code',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: payload.data.items.map(item => {\r\n return {\r\n label: item.name,\r\n value: "eq.".concat(item.id)\r\n }\r\n })\r\n}',
|
||||||
|
},
|
||||||
|
mode: 'inline',
|
||||||
|
size: 'md',
|
||||||
|
clearable: true,
|
||||||
|
className: 'm-l-sm',
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'group',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'tree-select',
|
||||||
|
label: '预留班级',
|
||||||
|
name: 'class_list',
|
||||||
|
mode: 'horizontal',
|
||||||
|
searchable: true,
|
||||||
|
clearable: true,
|
||||||
|
multiple: true,
|
||||||
|
joinValues: true,
|
||||||
|
onlyChildren: true,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/orgs?select=*&path=cd.root&order=name',
|
||||||
|
adaptor:
|
||||||
|
"const recursive = id => {\r\n let nodes = payload.data.items.filter(x => {\r\n return x.parent === id\r\n })\r\n\r\n return nodes.map(item => {\r\n return {\r\n ...item,\r\n label: item.name,\r\n value: item.id,\r\n children: recursive(item.id)\r\n }\r\n })\r\n}\r\n\r\nlet school = payload.data.items.find(x => x.type === 'school')\r\n\r\nreturn {\r\n ...payload,\r\n data: recursive(school.id)\r\n}\r\n",
|
||||||
|
},
|
||||||
|
withChildren: true,
|
||||||
|
initiallyOpen: false,
|
||||||
|
heightAuto: true,
|
||||||
|
virtualThreshold: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'group',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'switch',
|
||||||
|
name: 'no_tch',
|
||||||
|
mode: 'inline',
|
||||||
|
value: 0,
|
||||||
|
option: '显示无教师场次',
|
||||||
|
optionAtLeft: false,
|
||||||
|
trueValue: 1,
|
||||||
|
falseValue: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
mode: 'inline',
|
||||||
|
},
|
||||||
|
{ type: 'divider', lineStyle: 'solid' },
|
||||||
|
{
|
||||||
|
type: 'crud',
|
||||||
|
messages: {},
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/schedule_stats?organization_id=eq.$centre_id&semester_id=eq.$currentSemester&is_publish=is.true&order=date.asc,start_time.asc',
|
||||||
|
data: { page: '$page', perPage: '$perPage', '&': '$$' },
|
||||||
|
adaptor:
|
||||||
|
"let supportDateTimeFormat = typeof(Intl.DateTimeFormat) === 'function';\r\npayload.data.items.forEach((item,index) => {\r\n item.day = supportDateTimeFormat ? `${item.date}(${new Intl.DateTimeFormat('zh-CN', { weekday: 'short'}).format(new Date(item.date))})` : item.date;\r\n item.row_number = index + 1\r\n + (api.body.page - 1)\r\n * api.body.perPage\r\n let att_count = item.att_y_count\r\n + item.att_y_late_count\r\n + item.att_y_unclean_count\r\n item.att_num = \"\".concat(att_count, '/', item.current_student_number)\r\n item.att_num_status = att_count === item.current_student_number\r\n ? 1\r\n : 0\r\n item.stu_title = item.project_name.concat(\r\n ' :: ', item.date, ' ', item.period_name,\r\n ' :: ', item.location_name,\r\n ' :: ', item.teacher_name ? item.teacher_name : '无教师认领'\r\n )\r\n})\r\n\r\nreturn {\r\n ...payload\r\n}",
|
||||||
|
requestAdaptor:
|
||||||
|
"let url = api.url.replace(/project_id=&|teacher_id=&|date=&|location_id=&|no_tch=&|no_tch=0/g, '')\r\n\r\nif (api.body.class_list === '') {\r\n url = url.replace('&class_list=', '')\r\n} else {\r\n let class_list = api.body.class_list && api.body.class_list.replace(',', '%2C')\r\n url = url.replace(class_list, 'cs.{'.concat(class_list, '}'))\r\n}\r\n\r\nconst pattern = /(?:date=)(\\d+-\\d+-\\d+)%2C(\\d+-\\d+-\\d+)/g\r\nconst result = pattern.exec(url)\r\nif (result && result[1] === result[2]) {\r\n url = url.replace(result[0], 'date=eq.'.concat(result[1]))\r\n} else if (result) {\r\n url = url.replace(result[0], 'date=gte.'.concat(result[1], '&date=lte.', result[2]))\r\n} else {\r\n url = url.replace('&date=','')\r\n}\r\nconst is_no_tch = /no_tch=1/g.test(url)\r\nconst has_teacher = /teacher_id=.+?(?=&)/g.test(url)\r\nif (is_no_tch && has_teacher) {\r\n const teacher = /teacher_id=.+?(?=&)/g.exec(url)\r\n url = url.replace(teacher, 'or=('.concat(teacher, ',teacher_id.is.null)')).replace('teacher_id=', 'teacher_id.')\r\n url = url.replace(/no_tch=1/g, '')\r\n} else if (is_no_tch && !has_teacher) {\r\n url = url.replace(/no_tch=1/g, 'teacher_id=is.null')\r\n}\r\nreturn {\r\n ...api,\r\n url: url\r\n}",
|
||||||
|
},
|
||||||
|
syncLocation: false,
|
||||||
|
name: 'adopt',
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'row_number',
|
||||||
|
type: 'plain',
|
||||||
|
label: '序号',
|
||||||
|
tpl: '',
|
||||||
|
inline: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '',
|
||||||
|
type: 'tpl',
|
||||||
|
placeholder: '-',
|
||||||
|
label: '实验',
|
||||||
|
tpl: '<% if (this.scheduled_class_name) { %>\n <%= this.project_name %>(<%= this.scheduled_class_name %>)\n<% } else { %>\n <%= this.project_name %>\n<% } %>',
|
||||||
|
},
|
||||||
|
{ name: 'day', label: '日期', type: 'text', placeholder: '-' },
|
||||||
|
{ type: 'text', name: 'period_name', label: '节次', placeholder: '-' },
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
name: 'location_name',
|
||||||
|
placeholder: '-',
|
||||||
|
label: '地点',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'tpl',
|
||||||
|
label: '教师',
|
||||||
|
name: '',
|
||||||
|
placeholder: '-',
|
||||||
|
tpl: '<% if (this.teacher_name) { %>\n <span class="label label-info" style="font-size: smaller;"><%= this.teacher_name %></span>\n<% } else { %>\n <span class="label label-warning" style="font-size: smaller;">未认领</span>\n<% } %>',
|
||||||
|
inline: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'tpl',
|
||||||
|
label: '考勤状态',
|
||||||
|
placeholder: '-',
|
||||||
|
tpl: '<% if(this.att_num_status) { %>\n <span class="label label-success"><%= this.att_num %></span>\n<% } else { %>\n <span class="label label-warning"><%= this.att_num %></span>\n<% } %>',
|
||||||
|
inline: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button-group',
|
||||||
|
label: '操作',
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
label: '认领场次',
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'ajax',
|
||||||
|
level: 'success',
|
||||||
|
size: 'xs',
|
||||||
|
visibleOn:
|
||||||
|
"this.enableClaim && (this.user.role === 'teacher' && !this.teacher_id)",
|
||||||
|
api: {
|
||||||
|
method: 'patch',
|
||||||
|
url: 'rest/schedules/$id',
|
||||||
|
data: { teacher_id: '${user.id}' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '取消认领',
|
||||||
|
actionType: 'ajax',
|
||||||
|
level: 'danger',
|
||||||
|
size: 'xs',
|
||||||
|
visibleOn:
|
||||||
|
'this. enableClaim && this.teacher_code === this.user.code',
|
||||||
|
api: {
|
||||||
|
method: 'patch',
|
||||||
|
url: 'rest/schedules/$id',
|
||||||
|
data: { teacher_id: null },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '查看场次',
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '学生信息',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'crud',
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/user2projects?select=id,att_status,att_status_text:user2project_att_status_dict_fk(dictvalue),att_time,score,schedule_status:user2project_schedule_status_dict_fk(dictvalue),student:users!user2project_student_id_fkey(id,code,name,user_orgs(orgs(name)))&schedule_id=eq.${id}&schedule_status=in.(elected,stopped)&order=ordernumber_of_schedule',
|
||||||
|
data: null,
|
||||||
|
adaptor:
|
||||||
|
'payload.data.items.forEach((item,index) => {\r\n item.row_number=index+1;\r\n})\r\nreturn {\r\n ...payload\r\n}',
|
||||||
|
},
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
label: '序号',
|
||||||
|
type: 'plain',
|
||||||
|
inline: false,
|
||||||
|
name: 'row_number',
|
||||||
|
tpl: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '选课状态',
|
||||||
|
type: 'plain',
|
||||||
|
name: 'schedule_status.dictvalue',
|
||||||
|
placeholder: '-',
|
||||||
|
inline: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '学生',
|
||||||
|
name: 'student.name',
|
||||||
|
placeholder: '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '学号',
|
||||||
|
name: 'student.code',
|
||||||
|
placeholder: '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '班级',
|
||||||
|
name: 'student.user_orgs[0].orgs.name',
|
||||||
|
placeholder: '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'date',
|
||||||
|
label: '出勤',
|
||||||
|
name: 'att_time',
|
||||||
|
placeholder: '-',
|
||||||
|
format: 'YYYY-MM-DD HH:mm:ss',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '考勤状态',
|
||||||
|
name: 'att_status_text.dictvalue',
|
||||||
|
placeholder: '-',
|
||||||
|
groupName: '',
|
||||||
|
remark: '',
|
||||||
|
inline: true,
|
||||||
|
visibleOn:
|
||||||
|
"this.user.role !== 'teacher' || (this.user.role === 'teacher' && this.teacher_id === user.id)",
|
||||||
|
quickEdit: {
|
||||||
|
mode: 'popOver',
|
||||||
|
type: 'select',
|
||||||
|
label: '',
|
||||||
|
name: 'att_status',
|
||||||
|
checkAll: false,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/dicts?typecode=eq.014',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: payload.data.items.map(item => {\r\n return {\r\n label: item.dictvalue,\r\n value: item.dictkey\r\n }\r\n })\r\n}',
|
||||||
|
},
|
||||||
|
size: 'sm',
|
||||||
|
saveImmediately: {
|
||||||
|
api: {
|
||||||
|
method: 'patch',
|
||||||
|
url: 'rest/user2projects/${id}',
|
||||||
|
data: { att_status: '${att_status}' },
|
||||||
|
dataType: 'json',
|
||||||
|
requestAdaptor:
|
||||||
|
"let temp = api.data.att_status.slice(0, 5);\r\n\r\nif (temp === 'att_y') {\r\n let date = new Date();\r\n api.data.att_time=`${date.getFullYear()}-${date.getMonth()+1}-${date.getDate()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`;\r\n} else {\r\n api.data.att_time = null;\r\n}\r\n\r\nreturn api;",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '考勤状态',
|
||||||
|
name: 'att_status_text.dictvalue',
|
||||||
|
placeholder: '-',
|
||||||
|
groupName: '',
|
||||||
|
remark: '',
|
||||||
|
inline: true,
|
||||||
|
visibleOn:
|
||||||
|
"this.user.role === 'teacher' && this.teacher_id !== user.id",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
messages: {},
|
||||||
|
syncLocation: false,
|
||||||
|
bodyClassName: '',
|
||||||
|
className: '',
|
||||||
|
headerToolbar: [
|
||||||
|
'bulkActions',
|
||||||
|
{
|
||||||
|
type: 'tpl',
|
||||||
|
tpl: '${stu_title}',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '打印',
|
||||||
|
size: 'sm',
|
||||||
|
level: 'primary',
|
||||||
|
className: 'pull-right',
|
||||||
|
id: 'u:114eb8de43c8',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: true,
|
||||||
|
actionType: 'url',
|
||||||
|
args: {
|
||||||
|
url: '/admin/preview?id=${id}&project=${project_name}&location=${location_name}&teacher=${teacher_name}&date=${date}&start_time=${start_time}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'export-excel',
|
||||||
|
label: '全量导出 Excel',
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/user2projects?select=id,att_status,att_status_text:user2project_att_status_dict_fk(dictvalue),att_time,score,schedule_status:user2project_schedule_status_dict_fk(dictvalue),student:users!user2project_student_id_fkey(id,code,name,user_orgs(orgs(name)))&schedule_id=eq.${id}&schedule_status=in.(elected,stopped)&order=id.asc',
|
||||||
|
data: null,
|
||||||
|
adaptor:
|
||||||
|
'payload.data.items.forEach((item,index) => {\r\n item.row_number=index+1;\r\n})\r\nreturn {\r\n ...payload\r\n}',
|
||||||
|
},
|
||||||
|
filename: '考勤信息',
|
||||||
|
align: 'right',
|
||||||
|
id: 'u:d74fe0b275db',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
bulkActions: [
|
||||||
|
{
|
||||||
|
label: '批量考勤',
|
||||||
|
actionType: 'dialog',
|
||||||
|
type: 'button',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '批量考勤',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
controls: [
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
label: '选项',
|
||||||
|
name: 'att',
|
||||||
|
options: [],
|
||||||
|
checkAll: false,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/dicts?typecode=eq.014',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload.data,\r\n items: payload.data.items.map(item => {\r\n return {\r\n label: item.dictvalue,\r\n value: item.dictkey\r\n }\r\n })\r\n}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ type: 'hidden', name: 'id', value: '${ids}' },
|
||||||
|
],
|
||||||
|
wrapWithPanel: false,
|
||||||
|
initApi: '',
|
||||||
|
api: {
|
||||||
|
method: 'patch',
|
||||||
|
url: 'rest/user2projects?id=in.(${ids})',
|
||||||
|
data: { att_status: '$att' },
|
||||||
|
requestAdaptor:
|
||||||
|
"let temp = api.data.att_status.slice(0, 5);\r\n\r\nif (temp === 'att_y') {\r\n let date = new Date();\r\n api.data.att_time=`${date.getFullYear()}-${date.getMonth()+1}-${date.getDate()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`;\r\n} else {\r\n api.data.att_time = null;\r\n}\r\n\r\nreturn api;",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
},
|
||||||
|
visibleOn:
|
||||||
|
"this.user.role !== 'teacher' || (this.user.role === 'teacher' && this.teacher_id === user.id)",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
footerToolbar: [],
|
||||||
|
perPageField: '',
|
||||||
|
pageField: '',
|
||||||
|
affixHeader: false,
|
||||||
|
perPageAvailable: [10],
|
||||||
|
hideQuickSaveBtn: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closeOnEsc: true,
|
||||||
|
closeOnOutside: false,
|
||||||
|
showCloseButton: true,
|
||||||
|
size: 'lg',
|
||||||
|
actions: [],
|
||||||
|
},
|
||||||
|
level: 'primary',
|
||||||
|
size: 'xs',
|
||||||
|
reload: 'adopt',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
headerToolbar: [],
|
||||||
|
footerToolbar: [
|
||||||
|
{ type: 'pagination' },
|
||||||
|
{ type: 'switch-per-page' },
|
||||||
|
{ type: 'statistics' },
|
||||||
|
],
|
||||||
|
perPageAvailable: [10, 20, 30, 40, 50],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: 'page',
|
||||||
|
messages: {},
|
||||||
|
bodyClassName: '',
|
||||||
|
title: '',
|
||||||
|
style: {},
|
||||||
|
initApi: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/config?key=eq.system&organization_id=eq.${centre_id}',
|
||||||
|
adaptor:
|
||||||
|
'let item = payload.data.items[0];\r\nreturn {\r\n ...payload,\r\n data: {\r\n enableClaim: payload.data.items[0].value.enableClaim\r\n }\r\n}',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export { schema };
|
||||||
305
src/pages/schema/centre/att/machine.schema.ts
Normal file
305
src/pages/schema/centre/att/machine.schema.ts
Normal file
@@ -0,0 +1,305 @@
|
|||||||
|
const schema = {
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'panel',
|
||||||
|
className: 'Panel--default',
|
||||||
|
title: '',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'crud',
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/users_ex?select=organization_id:org_id,id,code,name,machine_locations(locations(id,name))&role=eq.machine&org_id=eq.$centre_id&order=code',
|
||||||
|
adaptor:
|
||||||
|
"return {\r\n ...payload,\r\n data: payload.data.items.map(item => {\r\n return {\r\n id: item.id,\r\n code: item.code,\r\n name: item.name,\r\n machine_locations: item.machine_locations,\r\n select_loc: item.machine_locations.map(item => {\r\n return ''.concat(item.locations.id)\r\n })\r\n }\r\n })\r\n}",
|
||||||
|
},
|
||||||
|
mode: 'cards',
|
||||||
|
messages: {},
|
||||||
|
card: {
|
||||||
|
type: 'card',
|
||||||
|
header: { title: '${code}', subTitle: '${name}' },
|
||||||
|
body: [
|
||||||
|
{ type: 'divider', label: '关联场地' },
|
||||||
|
{
|
||||||
|
type: 'button-group',
|
||||||
|
label: '',
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '',
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
title: '关联场地',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'rest/machine_locations',
|
||||||
|
dataType: 'json',
|
||||||
|
requestAdaptor:
|
||||||
|
'return {\r\n ...api,\r\n data: api.data.location_id.map(item => {\r\n return {\r\n user_id: api.data.id,\r\n location_id: item\r\n }\r\n })\r\n}',
|
||||||
|
adaptor: '',
|
||||||
|
},
|
||||||
|
title: '表单',
|
||||||
|
initApi: '',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'checkboxes',
|
||||||
|
label: '场地',
|
||||||
|
mode: '',
|
||||||
|
name: 'location_id',
|
||||||
|
required: true,
|
||||||
|
options: [],
|
||||||
|
joinValues: false,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/locations?id=not.in.(${select_loc})&organization_id=eq.$centre_id&order=code',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: payload.data.items.map(item => ({\r\n label: item.name,\r\n value: item.id\r\n }))\r\n}',
|
||||||
|
requestAdaptor: '',
|
||||||
|
},
|
||||||
|
extractValue: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: 'dialog',
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
},
|
||||||
|
icon: 'fa fa-plus text-primary',
|
||||||
|
level: 'link',
|
||||||
|
size: 'md',
|
||||||
|
tooltip: '关联场地',
|
||||||
|
tooltipPlacement: 'top',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'each',
|
||||||
|
name: 'machine_locations',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
type: 'container',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'tpl',
|
||||||
|
tpl: '${locations.name}',
|
||||||
|
inline: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'ajax',
|
||||||
|
confirmText: '确认取消关联"${locations.name}"?',
|
||||||
|
api: {
|
||||||
|
method: 'delete',
|
||||||
|
url: 'rest/machine_locations?user_id=eq.$id&location_id=eq.${locations.id}',
|
||||||
|
},
|
||||||
|
size: 'xs',
|
||||||
|
icon: 'fa fa-times text-danger',
|
||||||
|
level: 'link',
|
||||||
|
tooltip: '取消场地关联',
|
||||||
|
tooltipPlacement: 'top',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
className: 'wrapper',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
placeholder: '暂无内容',
|
||||||
|
className: '',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '',
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
api: {
|
||||||
|
method: 'patch',
|
||||||
|
url: 'rest/users/$id',
|
||||||
|
data: {
|
||||||
|
code: '$code',
|
||||||
|
name: '$name',
|
||||||
|
},
|
||||||
|
dataType: 'json',
|
||||||
|
},
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
label: '账号',
|
||||||
|
name: 'code',
|
||||||
|
required: true,
|
||||||
|
mode: 'normal',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '名称',
|
||||||
|
type: 'input-text',
|
||||||
|
name: 'name',
|
||||||
|
required: true,
|
||||||
|
mode: 'normal',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: 'dialog',
|
||||||
|
title: '修改考勤账号',
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
},
|
||||||
|
icon: 'fa fa-edit text-info',
|
||||||
|
level: 'link',
|
||||||
|
tooltip: '修改考勤账号',
|
||||||
|
tooltipPlacement: 'top',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '',
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '修改密码',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
rule: 'this.new_password === this.password',
|
||||||
|
message: '两次密码输入不一致',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'rest/rpc/change_password',
|
||||||
|
data: { password: '$password', user_id: '$id' },
|
||||||
|
},
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
label: '新密码',
|
||||||
|
type: 'input-password',
|
||||||
|
name: 'new_password',
|
||||||
|
required: true,
|
||||||
|
mode: 'normal',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-password',
|
||||||
|
label: '确认密码',
|
||||||
|
name: 'password',
|
||||||
|
required: true,
|
||||||
|
mode: 'normal',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
size: 'md',
|
||||||
|
},
|
||||||
|
icon: 'fa fa-cog text-warning',
|
||||||
|
tooltip: '修改密码',
|
||||||
|
tooltipPlacement: 'top',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '',
|
||||||
|
actionType: 'ajax',
|
||||||
|
icon: 'fa fa-trash text-danger',
|
||||||
|
confirmText: '确认删除"${name}(${code})"?',
|
||||||
|
api: { method: 'delete', url: 'rest/users/$id' },
|
||||||
|
level: 'link',
|
||||||
|
tooltip: '删除考勤账号',
|
||||||
|
tooltipPlacement: 'top',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
footerToolbar: [],
|
||||||
|
bulkActions: [],
|
||||||
|
className: '',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
header: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '添加考勤账号',
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
title: '添加考勤账号',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'rest/rpc/create_user',
|
||||||
|
data: {
|
||||||
|
role: 'machine',
|
||||||
|
orgs_id: '$centre_id',
|
||||||
|
code: '$code',
|
||||||
|
name: '$name',
|
||||||
|
password: '$password',
|
||||||
|
},
|
||||||
|
dataType: 'json',
|
||||||
|
headers: { Prefer: 'params=single-object' },
|
||||||
|
requestAdaptor: '',
|
||||||
|
},
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
rule: 'this.new_password === this.password',
|
||||||
|
message: '两次密码输入不一致',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
messages: {},
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
name: 'code',
|
||||||
|
label: '账号',
|
||||||
|
required: true,
|
||||||
|
mode: 'normal',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
label: '名称',
|
||||||
|
name: 'name',
|
||||||
|
required: true,
|
||||||
|
mode: 'normal',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '密码',
|
||||||
|
type: 'input-password',
|
||||||
|
name: 'new_password',
|
||||||
|
required: true,
|
||||||
|
mode: 'normal',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-password',
|
||||||
|
label: '确认密码',
|
||||||
|
name: 'password',
|
||||||
|
required: true,
|
||||||
|
mode: 'normal',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: 'dialog',
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
},
|
||||||
|
level: 'primary',
|
||||||
|
align: 'left',
|
||||||
|
className: 'm-t-xs m-l',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
headerClassName: 'panel-heading',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: 'page',
|
||||||
|
};
|
||||||
|
|
||||||
|
export { schema };
|
||||||
316
src/pages/schema/centre/basic/admin.schema.ts
Normal file
316
src/pages/schema/centre/basic/admin.schema.ts
Normal file
@@ -0,0 +1,316 @@
|
|||||||
|
const schema = {
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'crud',
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
name: 'code',
|
||||||
|
label: '账号',
|
||||||
|
placeholder: '-',
|
||||||
|
id: 'u:c3eb8f9b177e',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
name: 'name',
|
||||||
|
label: '姓名',
|
||||||
|
placeholder: '-',
|
||||||
|
id: 'u:6f74a11657ef',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button-group',
|
||||||
|
label: '操作',
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
level: 'link',
|
||||||
|
size: 'md',
|
||||||
|
icon: 'fa fa-pencil text-info',
|
||||||
|
visibleOn:
|
||||||
|
"this.user.role === 'dev' || this.user.role === 'admin'",
|
||||||
|
tooltip: '修改',
|
||||||
|
tooltipPlacement: 'top',
|
||||||
|
iconClassName: 'pull-left',
|
||||||
|
className: 'p-r-none p-l-none',
|
||||||
|
id: 'u:13770aa6289a',
|
||||||
|
editorState: 'default',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
title: '修改账号',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
api: {
|
||||||
|
method: 'patch',
|
||||||
|
url: 'rest/users/$id',
|
||||||
|
data: {
|
||||||
|
code: '$code',
|
||||||
|
name: '$name',
|
||||||
|
},
|
||||||
|
dataType: 'json',
|
||||||
|
},
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
label: '账号',
|
||||||
|
type: 'input-text',
|
||||||
|
name: 'code',
|
||||||
|
required: true,
|
||||||
|
mode: 'normal',
|
||||||
|
id: 'u:a614008003f6',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
label: '姓名',
|
||||||
|
name: 'name',
|
||||||
|
required: true,
|
||||||
|
mode: 'normal',
|
||||||
|
id: 'u:5973b1eb26ab',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:c59fb46c3665',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'submit',
|
||||||
|
label: 'Submit',
|
||||||
|
primary: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
feat: 'Insert',
|
||||||
|
dsType: 'api',
|
||||||
|
onEvent: {
|
||||||
|
submitSucc: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
componentId: 'u:366fea2f5de5',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'reload',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: 'dialog',
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
debounce: { wait: 100 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
confirmText: '确认删除账号"${name}(${code})"?',
|
||||||
|
level: 'link',
|
||||||
|
icon: 'fa fa-times text-danger',
|
||||||
|
size: 'md',
|
||||||
|
tooltip: '删除',
|
||||||
|
tooltipPlacement: 'bottom',
|
||||||
|
visibleOn:
|
||||||
|
"this.user.role === 'dev' || this.user.role === 'admin'",
|
||||||
|
iconClassName: 'pull-left',
|
||||||
|
className: 'p-r-none p-l-none',
|
||||||
|
id: 'u:221693061e9e',
|
||||||
|
editorState: 'default',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
outputVar: 'responseResult',
|
||||||
|
actionType: 'ajax',
|
||||||
|
options: {},
|
||||||
|
api: {
|
||||||
|
url: 'rest/users/$id',
|
||||||
|
method: 'delete',
|
||||||
|
requestAdaptor: '',
|
||||||
|
adaptor: '',
|
||||||
|
messages: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentId: 'u:366fea2f5de5',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'reload',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
debounce: { wait: 100 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
placeholder: '-',
|
||||||
|
width: 200,
|
||||||
|
id: 'u:96b309d3bf00',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
messages: {},
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/users?select=*&role=eq.centreadmin&user_orgs.orgs.id=eq.$centre_id&order=code',
|
||||||
|
data: { page: '$page', perPage: '$perPage' },
|
||||||
|
adaptor:
|
||||||
|
'payload.data.items.sort(\r\n (a, b) => {\r\n if (a.name === b.name) {\r\n return a.code.localeCompare(b.code)\r\n } else {\r\n return a.name.localeCompare(b.name)\r\n }\r\n }\r\n)\r\n\r\nreturn {\r\n ...payload\r\n}',
|
||||||
|
},
|
||||||
|
headerToolbar: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
icon: 'fa fa-plus text-primary',
|
||||||
|
size: 'lg',
|
||||||
|
level: 'link',
|
||||||
|
tooltip: '添加',
|
||||||
|
tooltipPlacement: 'left',
|
||||||
|
align: 'right',
|
||||||
|
label: '',
|
||||||
|
visibleOn: "this.user.role === 'dev' || this.user.role === 'admin'",
|
||||||
|
className: 'p-l-none',
|
||||||
|
id: 'u:76187972a571',
|
||||||
|
editorState: 'default',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '添加管理员',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'rest/rpc/create_user',
|
||||||
|
data: {
|
||||||
|
code: '$code',
|
||||||
|
name: '$name',
|
||||||
|
password: '$password',
|
||||||
|
new_password: '$new_password',
|
||||||
|
role: 'centreadmin',
|
||||||
|
orgs_id: '$centre_id',
|
||||||
|
},
|
||||||
|
dataType: 'json',
|
||||||
|
headers: { Prefer: 'params=single-object' },
|
||||||
|
},
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
label: '账号',
|
||||||
|
name: 'code',
|
||||||
|
required: true,
|
||||||
|
mode: 'normal',
|
||||||
|
id: 'u:6dca4e78622c',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
name: 'name',
|
||||||
|
label: '姓名',
|
||||||
|
mode: 'normal',
|
||||||
|
required: true,
|
||||||
|
id: 'u:56021033191e',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-password',
|
||||||
|
name: 'password',
|
||||||
|
label: '密码',
|
||||||
|
mode: 'normal',
|
||||||
|
required: true,
|
||||||
|
id: 'u:1b5ed3926797',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-password',
|
||||||
|
name: 'new_password',
|
||||||
|
label: '确认密码',
|
||||||
|
mode: 'normal',
|
||||||
|
required: true,
|
||||||
|
id: 'u:7c1e9ce050c0',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
rule: 'this.password === this.new_password',
|
||||||
|
message: '两次密码输入不一致,请重新输入',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:6ecfef8353a7',
|
||||||
|
actions: [
|
||||||
|
{ type: 'submit', label: '提交', primary: true },
|
||||||
|
],
|
||||||
|
feat: 'Insert',
|
||||||
|
onEvent: {
|
||||||
|
submitSucc: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
componentId: 'u:366fea2f5de5',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'reload',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
id: 'u:6179e3a79d93',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'cancel',
|
||||||
|
label: '取消',
|
||||||
|
id: 'u:e62e24a0fc22',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'confirm',
|
||||||
|
label: '确定',
|
||||||
|
primary: true,
|
||||||
|
id: 'u:f7524893881b',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
debounce: { wait: 100 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
syncLocation: false,
|
||||||
|
perPageAvailable: [10, 20, 30, 40, 50],
|
||||||
|
name: 'admin',
|
||||||
|
footerToolbar: [
|
||||||
|
{ type: 'pagination' },
|
||||||
|
{ type: 'switch-per-page' },
|
||||||
|
{ type: 'statistics' },
|
||||||
|
],
|
||||||
|
perPageField: 'perPage',
|
||||||
|
bulkActions: [],
|
||||||
|
itemActions: [],
|
||||||
|
pageField: 'page',
|
||||||
|
affixHeader: true,
|
||||||
|
id: 'u:366fea2f5de5',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: 'page',
|
||||||
|
messages: {},
|
||||||
|
title: '',
|
||||||
|
perPageAvailable: [10, 20, 30, 40, 50],
|
||||||
|
id: 'u:4c19431ee5db',
|
||||||
|
};
|
||||||
|
|
||||||
|
export { schema };
|
||||||
474
src/pages/schema/centre/basic/assistant.schema.ts
Normal file
474
src/pages/schema/centre/basic/assistant.schema.ts
Normal file
@@ -0,0 +1,474 @@
|
|||||||
|
const schema = {
|
||||||
|
type: 'page',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'crud',
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
name: 'code',
|
||||||
|
label: '账号',
|
||||||
|
sortable: true,
|
||||||
|
searchable: true,
|
||||||
|
id: 'u:91821b736555',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
name: 'name',
|
||||||
|
label: '姓名',
|
||||||
|
sortable: true,
|
||||||
|
searchable: true,
|
||||||
|
id: 'u:a81612f6d91c',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button-group',
|
||||||
|
label: '操作',
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
level: 'link',
|
||||||
|
size: 'md',
|
||||||
|
icon: 'fa fa-pencil text-info',
|
||||||
|
tooltip: '修改',
|
||||||
|
tooltipPlacement: 'top',
|
||||||
|
iconClassName: 'pull-left',
|
||||||
|
className: 'p-r-none p-l-none',
|
||||||
|
label: '',
|
||||||
|
api: { method: 'get', url: 'rest/users/$id' },
|
||||||
|
id: 'u:483a2e18377b',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
title: '修改账号',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
api: {
|
||||||
|
method: 'patch',
|
||||||
|
url: 'rest/users/$id',
|
||||||
|
data: { code: '$code', name: '$name' },
|
||||||
|
dataType: 'json',
|
||||||
|
},
|
||||||
|
mode: 'normal',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
label: '账号',
|
||||||
|
type: 'input-text',
|
||||||
|
name: 'code',
|
||||||
|
required: true,
|
||||||
|
id: 'u:bcbd9ab0fd9e',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
label: '姓名',
|
||||||
|
name: 'name',
|
||||||
|
required: true,
|
||||||
|
id: 'u:3b7829fa16f8',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:7a2ac32b9e2b',
|
||||||
|
actions: [
|
||||||
|
{ type: 'submit', label: '提交', primary: true },
|
||||||
|
],
|
||||||
|
feat: 'Insert',
|
||||||
|
dsType: 'api',
|
||||||
|
onEvent: {
|
||||||
|
submitSucc: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
componentId: 'u:f1b328630134',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'reload',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: 'dialog',
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
id: 'u:49ea67f4ccca',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'cancel',
|
||||||
|
label: '取消',
|
||||||
|
id: 'u:e22fba76fe33',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'confirm',
|
||||||
|
label: '确定',
|
||||||
|
primary: true,
|
||||||
|
id: 'u:46273e3a4090',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
actionType: 'dialog',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
confirmText: '确认删除"${name}(${code})"?',
|
||||||
|
level: 'link',
|
||||||
|
icon: 'fa fa-times text-danger',
|
||||||
|
size: 'md',
|
||||||
|
tooltip: '删除',
|
||||||
|
tooltipPlacement: 'top',
|
||||||
|
iconClassName: 'pull-left',
|
||||||
|
className: 'p-r-none p-l-none',
|
||||||
|
label: '',
|
||||||
|
id: 'u:c3026515a2de',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
outputVar: 'responseResult',
|
||||||
|
actionType: 'ajax',
|
||||||
|
options: {},
|
||||||
|
api: {
|
||||||
|
url: 'rest/users/$id',
|
||||||
|
method: 'delete',
|
||||||
|
requestAdaptor: '',
|
||||||
|
adaptor: '',
|
||||||
|
messages: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentId: 'u:f1b328630134',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'reload',
|
||||||
|
args: { resetPage: false },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
placeholder: '-',
|
||||||
|
width: 200,
|
||||||
|
id: 'u:e8398dbbd899',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
messages: {},
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/users?select=*,user_orgs(orgs(id))&code=${code}&name=${name}&role=eq.assistant&user_orgs.orgs.id=eq.$centre_id&order=code',
|
||||||
|
data: {
|
||||||
|
page: '${page}',
|
||||||
|
perPage: '${perPage}',
|
||||||
|
orderBy: '${orderBy}',
|
||||||
|
orderDir: '${orderDir}',
|
||||||
|
code: 'like.%${code}%',
|
||||||
|
name: 'like.%${name}%',
|
||||||
|
},
|
||||||
|
requestAdaptor:
|
||||||
|
"if (api.query.code === 'like.%%') {\r\n api.url = api.url.replace('&code=like.%25%25', '')\r\n}\r\n\r\nif (api.query.name === 'like.%%') {\r\n api.url = api.url.replace('&name=like.%25%25', '')\r\n}\r\n\r\nif (api.query.orderDir) {\r\n api.url = api.url.replace('&order=code%2Cname', '');\r\n api.url = api.url.replace('&orderBy=' + api.query.orderBy + '&orderDir=' + api.query.orderDir, '&order=' + api.query.orderBy + '.' + api.query.orderDir);\r\n} else if (api.query.orderBy) {\r\n api.url = api.url.replace('&order=code%2Cname', '');\r\n api.url = api.url.replace('&orderBy=' + api.query.orderBy + '&orderDir=', '&order=' + api.query.orderBy);\r\n} else {\r\n api.url = api.url.replace('&orderBy=&orderDir=', '');\r\n}\r\n\r\nreturn api;",
|
||||||
|
},
|
||||||
|
headerToolbar: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
icon: 'fa fa-plus',
|
||||||
|
level: 'default',
|
||||||
|
align: 'right',
|
||||||
|
label: '添加',
|
||||||
|
className: 'm-l-xs',
|
||||||
|
id: 'u:ab332275c1fa',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '添加助教',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
name: 'code',
|
||||||
|
label: '账号',
|
||||||
|
mode: 'normal',
|
||||||
|
required: true,
|
||||||
|
id: 'u:487b8805e663',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
name: 'name',
|
||||||
|
label: '姓名',
|
||||||
|
mode: 'normal',
|
||||||
|
required: true,
|
||||||
|
id: 'u:89de05a91f91',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-password',
|
||||||
|
name: 'password',
|
||||||
|
label: '密码',
|
||||||
|
mode: 'normal',
|
||||||
|
required: true,
|
||||||
|
id: 'u:0fb31870de06',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-password',
|
||||||
|
name: 'new_password',
|
||||||
|
label: '确认密码',
|
||||||
|
mode: 'normal',
|
||||||
|
required: true,
|
||||||
|
id: 'u:c78103928eff',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'rest/rpc/create_user',
|
||||||
|
data: {
|
||||||
|
code: '$code',
|
||||||
|
name: '$name',
|
||||||
|
password: '$password',
|
||||||
|
new_password: '$new_password',
|
||||||
|
role: 'assistant',
|
||||||
|
orgs_id: '$centre_id',
|
||||||
|
},
|
||||||
|
requestAdaptor: '',
|
||||||
|
dataType: 'json',
|
||||||
|
headers: { Prefer: 'params=single-object' },
|
||||||
|
},
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
rule: 'this.password === this.new_password',
|
||||||
|
message: '两次密码输入不一致,请重新输入',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:b610d21f422f',
|
||||||
|
actions: [
|
||||||
|
{ type: 'submit', label: '提交', primary: true },
|
||||||
|
],
|
||||||
|
feat: 'Insert',
|
||||||
|
dsType: 'api',
|
||||||
|
onEvent: {
|
||||||
|
submitSucc: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
componentId: 'u:f1b328630134',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'reload',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
closeOnOutside: false,
|
||||||
|
id: 'u:2fbf0844aca1',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'cancel',
|
||||||
|
label: '取消',
|
||||||
|
id: 'u:deb6bbf65621',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'confirm',
|
||||||
|
label: '确定',
|
||||||
|
primary: true,
|
||||||
|
id: 'u:bbdffe4baf61',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
actionType: 'dialog',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tooltip: '',
|
||||||
|
tooltipPlacement: 'left',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
align: 'right',
|
||||||
|
label: '导入',
|
||||||
|
icon: 'fa fa-upload',
|
||||||
|
level: 'warning',
|
||||||
|
id: 'u:6581af7e35f0',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '助教导入',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'input-excel',
|
||||||
|
name: 'assistants',
|
||||||
|
label: '',
|
||||||
|
mode: 'normal',
|
||||||
|
id: 'u:5f0eca8a64fc',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-table',
|
||||||
|
name: 'assistants',
|
||||||
|
label: '',
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
label: '账号',
|
||||||
|
name: '账号',
|
||||||
|
placeholder: '-',
|
||||||
|
quickEdit: {
|
||||||
|
mode: 'inline',
|
||||||
|
id: 'u:fcf8c77a0302',
|
||||||
|
},
|
||||||
|
id: 'u:328345552f87',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '姓名',
|
||||||
|
name: '姓名',
|
||||||
|
placeholder: '-',
|
||||||
|
quickEdit: {
|
||||||
|
mode: 'inline',
|
||||||
|
id: 'u:3801de195dcc',
|
||||||
|
},
|
||||||
|
id: 'u:e3d8eb8dae09',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
mode: 'normal',
|
||||||
|
visibleOn: 'this.assistants',
|
||||||
|
strictMode: true,
|
||||||
|
removable: true,
|
||||||
|
editable: false,
|
||||||
|
id: 'u:d73c846629ed',
|
||||||
|
clearValueOnHidden: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'rest/rpc/create_user',
|
||||||
|
data: {
|
||||||
|
orgs_id: '${centre_id}',
|
||||||
|
assistants: '${assistants}',
|
||||||
|
},
|
||||||
|
requestAdaptor:
|
||||||
|
"return {\r\n ...api,\r\n data: api.data.assistants.map(item => {\r\n return {\r\n name: item.姓名,\r\n code: item.账号,\r\n role: 'assistant',\r\n orgs_id: api.data.orgs_id\r\n }\r\n })\r\n}",
|
||||||
|
dataType: 'json',
|
||||||
|
headers: { Prefer: 'params=single-object' },
|
||||||
|
},
|
||||||
|
visibleOn: '',
|
||||||
|
name: '',
|
||||||
|
id: 'u:feda7d9a6c8e',
|
||||||
|
actions: [
|
||||||
|
{ type: 'submit', label: '提交', primary: true },
|
||||||
|
],
|
||||||
|
feat: 'Insert',
|
||||||
|
dsType: 'api',
|
||||||
|
onEvent: {
|
||||||
|
submitSucc: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
componentId: 'u:f1b328630134',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'reload',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
size: 'xl',
|
||||||
|
actionType: 'dialog',
|
||||||
|
id: 'u:7cc3f8103868',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'cancel',
|
||||||
|
label: '取消',
|
||||||
|
id: 'u:908813bc5040',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'confirm',
|
||||||
|
label: '确定',
|
||||||
|
primary: true,
|
||||||
|
id: 'u:280fe6e082d4',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closeOnOutside: false,
|
||||||
|
showErrorMsg: true,
|
||||||
|
showLoading: true,
|
||||||
|
draggable: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'export-excel',
|
||||||
|
align: 'right',
|
||||||
|
label: '导出',
|
||||||
|
icon: 'fa fa-download',
|
||||||
|
level: 'primary',
|
||||||
|
api: 'rest/users?select=*,user_orgs(orgs(id))&role=eq.assistant&user_orgs.orgs.id=eq.$centre_id&order=code',
|
||||||
|
filename: '助教管理',
|
||||||
|
exportColumns: [
|
||||||
|
{ label: '账号', name: 'code' },
|
||||||
|
{ name: 'name', label: '姓名' },
|
||||||
|
],
|
||||||
|
id: 'u:556c3974c544',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
syncLocation: false,
|
||||||
|
perPageAvailable: [10, 20, 30, 40, 50],
|
||||||
|
footerToolbar: [
|
||||||
|
{ type: 'pagination' },
|
||||||
|
{ type: 'switch-per-page' },
|
||||||
|
{ type: 'statistics' },
|
||||||
|
],
|
||||||
|
perPageField: 'perPage',
|
||||||
|
pageField: 'page',
|
||||||
|
affixHeader: true,
|
||||||
|
title: '',
|
||||||
|
initApi: '',
|
||||||
|
bodyClassName: '',
|
||||||
|
id: 'u:f1b328630134',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
messages: {},
|
||||||
|
title: '',
|
||||||
|
id: 'u:31753e0403ea',
|
||||||
|
asideResizor: false,
|
||||||
|
pullRefresh: { disabled: true },
|
||||||
|
definitions: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
export { schema };
|
||||||
493
src/pages/schema/centre/basic/location.schema.ts
Normal file
493
src/pages/schema/centre/basic/location.schema.ts
Normal file
@@ -0,0 +1,493 @@
|
|||||||
|
const schema = {
|
||||||
|
type: 'page',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'crud',
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
name: 'code',
|
||||||
|
label: '编号',
|
||||||
|
sortable: true,
|
||||||
|
searchable: true,
|
||||||
|
id: 'u:f01745729d6f',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
name: 'name',
|
||||||
|
label: '名称',
|
||||||
|
sortable: true,
|
||||||
|
searchable: true,
|
||||||
|
id: 'u:0db1a83903b6',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '类型',
|
||||||
|
id: 'u:00332fcfb6b6',
|
||||||
|
name: 'dicts.dictvalue',
|
||||||
|
searchable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button-group',
|
||||||
|
label: '操作',
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: { $ref: 'dialog-ref-2' },
|
||||||
|
level: 'link',
|
||||||
|
size: 'md',
|
||||||
|
icon: 'fa fa-pencil text-info',
|
||||||
|
tooltip: '修改',
|
||||||
|
tooltipPlacement: 'top',
|
||||||
|
iconClassName: 'pull-left',
|
||||||
|
className: 'p-r-none p-l-none',
|
||||||
|
id: 'u:2fbcae5dec1e',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: { $ref: 'dialog-ref-2' },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
confirmText: '确认删除"${name}(${code})"?',
|
||||||
|
level: 'link',
|
||||||
|
icon: 'fa fa-times text-danger',
|
||||||
|
size: 'md',
|
||||||
|
tooltip: '删除',
|
||||||
|
tooltipPlacement: 'top',
|
||||||
|
iconClassName: 'pull-left',
|
||||||
|
className: 'p-r-none p-l-none',
|
||||||
|
id: 'u:259ec9a26f44',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
outputVar: 'responseResult',
|
||||||
|
actionType: 'ajax',
|
||||||
|
options: {},
|
||||||
|
api: {
|
||||||
|
url: 'rest/locations/$id',
|
||||||
|
method: 'delete',
|
||||||
|
requestAdaptor: '',
|
||||||
|
adaptor: '',
|
||||||
|
messages: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentId: 'u:96cb5c2c87a4',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'reload',
|
||||||
|
args: { resetPage: false },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
placeholder: '-',
|
||||||
|
width: 200,
|
||||||
|
id: 'u:328bf6132313',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
messages: {},
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/locations?select=id,code,name,type,dicts!inner(dictvalue)&code=${code}&name=${name}&dicts.dictvalue=${dicts.dictvalue}&order=code',
|
||||||
|
data: {
|
||||||
|
page: '${page}',
|
||||||
|
perPage: '${perPage}',
|
||||||
|
orderBy: '${orderBy}',
|
||||||
|
orderDir: '${orderDir}',
|
||||||
|
code: 'like.%${code}%',
|
||||||
|
name: 'like.%${name}%',
|
||||||
|
'dicts.dictvalue': 'like.%${dicts.dictvalue}%',
|
||||||
|
},
|
||||||
|
requestAdaptor:
|
||||||
|
"if (api.query.code === 'like.%%') {\r\n api.url = api.url.replace('&code=like.%25%25', '')\r\n}\r\n\r\nif (api.query.name === 'like.%%') {\r\n api.url = api.url.replace('&name=like.%25%25', '')\r\n}\r\n\r\nif (api.query.dicts.dictvalue === 'like.%%') {\r\n api.url = api.url.replace('&dicts[dictvalue]=like.%25%25', '')\r\n}\r\n\r\nif (api.query.orderDir) {\r\n api.url = api.url.replace('&order=code%2Cname', '');\r\n api.url = api.url.replace('&orderBy=' + api.query.orderBy + '&orderDir=' + api.query.orderDir, '&order=' + api.query.orderBy + '.' + api.query.orderDir);\r\n} else if (api.query.orderBy) {\r\n api.url = api.url.replace('&order=code%2Cname', '');\r\n api.url = api.url.replace('&orderBy=' + api.query.orderBy + '&orderDir=', '&order=' + api.query.orderBy);\r\n} else {\r\n api.url = api.url.replace('&orderBy=&orderDir=', '');\r\n}\r\n\r\nreturn api;",
|
||||||
|
},
|
||||||
|
headerToolbar: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
icon: 'fa fa-plus',
|
||||||
|
level: 'default',
|
||||||
|
align: 'right',
|
||||||
|
label: '添加',
|
||||||
|
className: 'm-l-xs',
|
||||||
|
id: 'u:64fb6bec0fff',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: { $ref: 'dialog-ref-1' },
|
||||||
|
args: { fromCurrentDialog: true },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: { $ref: 'dialog-ref-1' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
align: 'right',
|
||||||
|
label: '导入',
|
||||||
|
icon: 'fa fa-upload',
|
||||||
|
level: 'warning',
|
||||||
|
id: 'u:a2c775bee2a9',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '场地导入',
|
||||||
|
size: 'lg',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
id: 'u:2d97745994e5',
|
||||||
|
title: '表单',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'input-excel',
|
||||||
|
name: 'locations',
|
||||||
|
label: '',
|
||||||
|
mode: 'normal',
|
||||||
|
id: 'u:5f0eca8a64fc',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-table',
|
||||||
|
name: 'locations',
|
||||||
|
label: '',
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
label: '编号',
|
||||||
|
name: '编号',
|
||||||
|
placeholder: '-',
|
||||||
|
quickEdit: {
|
||||||
|
mode: 'inline',
|
||||||
|
id: 'u:931a41e1011d',
|
||||||
|
},
|
||||||
|
id: 'u:0c6672aa1858',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '名称',
|
||||||
|
name: '名称',
|
||||||
|
placeholder: '-',
|
||||||
|
quickEdit: {
|
||||||
|
mode: 'inline',
|
||||||
|
id: 'u:6ebc04992e03',
|
||||||
|
},
|
||||||
|
id: 'u:a03852887668',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '类型',
|
||||||
|
name: '类型',
|
||||||
|
placeholder: '-',
|
||||||
|
quickEdit: {
|
||||||
|
mode: 'inline',
|
||||||
|
id: 'u:a75f5e419328',
|
||||||
|
},
|
||||||
|
id: 'u:efedd284d265',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
mode: 'normal',
|
||||||
|
visibleOn: 'this.locations',
|
||||||
|
strictMode: true,
|
||||||
|
removable: true,
|
||||||
|
editable: false,
|
||||||
|
id: 'u:d73c846629ed',
|
||||||
|
clearValueOnHidden: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'rest/locations',
|
||||||
|
data: {
|
||||||
|
orgs_id: '${centre_id}',
|
||||||
|
locations: '${locations}',
|
||||||
|
},
|
||||||
|
requestAdaptor:
|
||||||
|
"return {\r\n ...api,\r\n data: api.data.locations.map(item => {\r\n let type;\r\n switch (item.类型)\r\n {\r\n case '实验室':\r\n type = 'laboratory';\r\n break;\r\n case '教室':\r\n type = 'classroom';\r\n break;\r\n case '办公室':\r\n type = 'office';\r\n break;\r\n case '仓库':\r\n typ = 'warehouse';\r\n break;\r\n }\r\n\r\n return {\r\n name: item.名称,\r\n code: item.编号,\r\n type: type,\r\n organization_id: api.data.orgs_id\r\n }\r\n })\r\n}",
|
||||||
|
dataType: 'json',
|
||||||
|
},
|
||||||
|
visibleOn: '',
|
||||||
|
name: '',
|
||||||
|
actions: [
|
||||||
|
{ type: 'submit', label: '提交', primary: true },
|
||||||
|
],
|
||||||
|
feat: 'Insert',
|
||||||
|
dsType: 'api',
|
||||||
|
labelAlign: 'left',
|
||||||
|
onEvent: {
|
||||||
|
submitSucc: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
componentId: 'u:96cb5c2c87a4',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'reload',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
actionType: 'dialog',
|
||||||
|
id: 'u:438767684afb',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'cancel',
|
||||||
|
label: '取消',
|
||||||
|
id: 'u:c664b67b3e6b',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'confirm',
|
||||||
|
label: '确定',
|
||||||
|
primary: true,
|
||||||
|
id: 'u:f8fa25c49d82',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'export-excel',
|
||||||
|
align: 'right',
|
||||||
|
label: '导出',
|
||||||
|
icon: 'fa fa-download',
|
||||||
|
level: 'primary',
|
||||||
|
api: 'rest/locations?select=id,code,name,type,dicts(dictvalue)&order=code',
|
||||||
|
filename: '实验场地',
|
||||||
|
exportColumns: [
|
||||||
|
{ label: '编号', name: 'code' },
|
||||||
|
{ name: 'name', label: '名称' },
|
||||||
|
{ name: 'dicts.dictvalue', label: '类型' },
|
||||||
|
],
|
||||||
|
id: 'u:ab01cbc28399',
|
||||||
|
perPageAvailable: [10],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
syncLocation: false,
|
||||||
|
perPageAvailable: [10, 20, 30, 40, 50],
|
||||||
|
footerToolbar: [
|
||||||
|
{ type: 'pagination' },
|
||||||
|
{ type: 'switch-per-page' },
|
||||||
|
{ type: 'statistics' },
|
||||||
|
],
|
||||||
|
perPageField: 'perPage',
|
||||||
|
pageField: 'page',
|
||||||
|
title: '',
|
||||||
|
initApi: '',
|
||||||
|
bodyClassName: '',
|
||||||
|
id: 'u:96cb5c2c87a4',
|
||||||
|
initFetch: '',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
messages: {},
|
||||||
|
title: '',
|
||||||
|
id: 'u:4ffd31a5304f',
|
||||||
|
definitions: {
|
||||||
|
'dialog-ref-1': {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '添加实验场地',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
name: 'code',
|
||||||
|
label: '编号',
|
||||||
|
mode: 'normal',
|
||||||
|
required: true,
|
||||||
|
id: 'u:9736564ec7fc',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
name: 'name',
|
||||||
|
label: '名称',
|
||||||
|
mode: 'normal',
|
||||||
|
required: true,
|
||||||
|
id: 'u:dcb5e881be78',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
name: 'type',
|
||||||
|
label: '类型',
|
||||||
|
mode: 'normal',
|
||||||
|
required: true,
|
||||||
|
checkAll: false,
|
||||||
|
source: {
|
||||||
|
url: 'rest/dicts?typecode=eq.006',
|
||||||
|
method: 'get',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: payload.data.items.map((item) => {\r\n return {\r\n label: item.dictvalue,\r\n value: item.dictkey\r\n };\r\n })\r\n}',
|
||||||
|
},
|
||||||
|
value: 'laboratory',
|
||||||
|
options: [{ label: '实验室', value: 'laboratory' }],
|
||||||
|
id: 'u:af3f658e33cf',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'rest/locations',
|
||||||
|
data: {
|
||||||
|
code: '$code',
|
||||||
|
name: '$name',
|
||||||
|
type: '$type',
|
||||||
|
organization_id: '${centre_id}',
|
||||||
|
},
|
||||||
|
dataType: 'json',
|
||||||
|
},
|
||||||
|
id: 'u:510d0236a371',
|
||||||
|
actions: [{ type: 'submit', label: '提交', primary: true }],
|
||||||
|
feat: 'Insert',
|
||||||
|
dsType: 'api',
|
||||||
|
onEvent: {
|
||||||
|
submitSucc: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
componentId: 'u:96cb5c2c87a4',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'reload',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
id: 'u:9cae782cb189',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'cancel',
|
||||||
|
label: '取消',
|
||||||
|
id: 'u:5217a0785f6c',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'confirm',
|
||||||
|
label: '确定',
|
||||||
|
primary: true,
|
||||||
|
id: 'u:1e10c45aa1a2',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
$$ref: 'dialog-ref-1',
|
||||||
|
},
|
||||||
|
'dialog-ref-2': {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '修改实验场地',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
api: {
|
||||||
|
method: 'patch',
|
||||||
|
url: 'rest/locations?id=eq.$id',
|
||||||
|
data: { code: '$code', name: '$name', type: '$type' },
|
||||||
|
dataType: 'json',
|
||||||
|
},
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
label: '编号',
|
||||||
|
type: 'input-text',
|
||||||
|
name: 'code',
|
||||||
|
required: true,
|
||||||
|
mode: 'normal',
|
||||||
|
id: 'u:339d0f396a34',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
label: '名称',
|
||||||
|
name: 'name',
|
||||||
|
required: true,
|
||||||
|
mode: 'normal',
|
||||||
|
id: 'u:3f1f8e6f2f13',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'type',
|
||||||
|
type: 'select',
|
||||||
|
label: '类型',
|
||||||
|
source: {
|
||||||
|
url: 'rest/dicts?typecode=eq.006',
|
||||||
|
method: 'get',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: payload.data.items.map((item) => {\r\n return {\r\n label: item.dictvalue,\r\n value: item.dictkey,\r\n };\r\n }),\r\n};',
|
||||||
|
},
|
||||||
|
required: true,
|
||||||
|
checkAll: false,
|
||||||
|
mode: 'normal',
|
||||||
|
id: 'u:fda206c44f88',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:3ab6c9e29cf6',
|
||||||
|
actions: [{ type: 'submit', label: '提交', primary: true }],
|
||||||
|
feat: 'Insert',
|
||||||
|
dsType: 'api',
|
||||||
|
onEvent: {
|
||||||
|
submitSucc: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
componentId: 'u:96cb5c2c87a4',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'reload',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
id: 'u:786fa30ccac8',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'cancel',
|
||||||
|
label: '取消',
|
||||||
|
id: 'u:d81e2b6865c1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'confirm',
|
||||||
|
label: '确定',
|
||||||
|
primary: true,
|
||||||
|
id: 'u:e76ad8a24b48',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
$$ref: 'dialog-ref-2',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export { schema };
|
||||||
1164
src/pages/schema/centre/basic/settings.schema.ts
Normal file
1164
src/pages/schema/centre/basic/settings.schema.ts
Normal file
File diff suppressed because it is too large
Load Diff
485
src/pages/schema/centre/basic/teacher.schema.ts
Normal file
485
src/pages/schema/centre/basic/teacher.schema.ts
Normal file
@@ -0,0 +1,485 @@
|
|||||||
|
const schema = {
|
||||||
|
type: 'page',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'crud',
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
name: 'code',
|
||||||
|
label: '账号',
|
||||||
|
sortable: true,
|
||||||
|
searchable: true,
|
||||||
|
id: 'u:815ab28420f2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
name: 'name',
|
||||||
|
label: '姓名',
|
||||||
|
sortable: true,
|
||||||
|
searchable: true,
|
||||||
|
id: 'u:14ae63b2e9b2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button-group',
|
||||||
|
label: '操作',
|
||||||
|
id: 'u:70fc12c2dc93',
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
level: 'link',
|
||||||
|
size: 'md',
|
||||||
|
icon: 'fa fa-pencil text-info',
|
||||||
|
tooltip: '修改',
|
||||||
|
tooltipPlacement: 'top',
|
||||||
|
iconClassName: 'pull-left',
|
||||||
|
className: 'p-r-none p-l-none',
|
||||||
|
label: '',
|
||||||
|
api: { method: 'get', url: 'rest/users/$id' },
|
||||||
|
id: 'u:0e1e6868a15e',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
title: '修改账号',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
api: {
|
||||||
|
method: 'patch',
|
||||||
|
url: 'rest/users/$id',
|
||||||
|
data: { code: '$code', name: '$name' },
|
||||||
|
dataType: 'json',
|
||||||
|
},
|
||||||
|
mode: 'normal',
|
||||||
|
id: 'u:752cc90e2438',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
label: '账号',
|
||||||
|
type: 'input-text',
|
||||||
|
name: 'code',
|
||||||
|
required: true,
|
||||||
|
id: 'u:dab5b6824746',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
label: '姓名',
|
||||||
|
name: 'name',
|
||||||
|
required: true,
|
||||||
|
id: 'u:95086c61998e',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
actions: [
|
||||||
|
{ type: 'submit', label: '提交', primary: true },
|
||||||
|
],
|
||||||
|
feat: 'Insert',
|
||||||
|
dsType: 'api',
|
||||||
|
onEvent: {
|
||||||
|
submitSucc: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
componentId: 'u:de2533791a72',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'reload',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: 'dialog',
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
id: 'u:41bebd8f0aba',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'cancel',
|
||||||
|
label: '取消',
|
||||||
|
id: 'u:7aabbd45b9b9',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'confirm',
|
||||||
|
label: '确定',
|
||||||
|
primary: true,
|
||||||
|
id: 'u:d1ba4fdace4d',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
actionType: 'dialog',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
confirmText: '确认删除"${name}(${code})"?',
|
||||||
|
level: 'link',
|
||||||
|
icon: 'fa fa-times text-danger',
|
||||||
|
size: 'md',
|
||||||
|
tooltip: '删除',
|
||||||
|
tooltipPlacement: 'bottom',
|
||||||
|
iconClassName: 'pull-left',
|
||||||
|
className: 'p-r-none p-l-none',
|
||||||
|
label: '',
|
||||||
|
id: 'u:b9864828c5ea',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
outputVar: 'responseResult',
|
||||||
|
actionType: 'ajax',
|
||||||
|
options: {},
|
||||||
|
api: {
|
||||||
|
url: 'rest/users/$id',
|
||||||
|
method: 'delete',
|
||||||
|
requestAdaptor: '',
|
||||||
|
adaptor: '',
|
||||||
|
messages: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentId: 'u:de2533791a72',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'reload',
|
||||||
|
args: { resetPage: false },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '',
|
||||||
|
actionType: 'ajax',
|
||||||
|
size: 'md',
|
||||||
|
level: 'link',
|
||||||
|
icon: 'fa fa-cog text-warning',
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'rest/rpc/reset_password',
|
||||||
|
data: { user_id: '$id' },
|
||||||
|
},
|
||||||
|
confirmText: '确认重置"${name}"的密码?',
|
||||||
|
visibleOn: '',
|
||||||
|
tooltip: '重置密码',
|
||||||
|
tooltipPlacement: 'top',
|
||||||
|
iconClassName: 'pull-left',
|
||||||
|
className: 'p-r-none p-l-none',
|
||||||
|
id: 'u:b7b4f65ce939',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
placeholder: '-',
|
||||||
|
width: 200,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
messages: {},
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/users?select=*,user_orgs(orgs(id))&code=${code}&name=${name}&role=eq.teacher&user_orgs.orgs.id=eq.$centre_id&order=code',
|
||||||
|
data: {
|
||||||
|
page: '${page}',
|
||||||
|
perPage: '${perPage}',
|
||||||
|
orderBy: '${orderBy}',
|
||||||
|
orderDir: '${orderDir}',
|
||||||
|
code: 'like.%${code}%',
|
||||||
|
name: 'like.%${name}%',
|
||||||
|
},
|
||||||
|
requestAdaptor:
|
||||||
|
"if (api.query.code === 'like.%%') {\r\n api.url = api.url.replace('&code=like.%25%25', '')\r\n}\r\n\r\nif (api.query.name === 'like.%%') {\r\n api.url = api.url.replace('&name=like.%25%25', '')\r\n}\r\n\r\nif (api.query.orderDir) {\r\n api.url = api.url.replace('&order=code%2Cname', '');\r\n api.url = api.url.replace('&orderBy=' + api.query.orderBy + '&orderDir=' + api.query.orderDir, '&order=' + api.query.orderBy + '.' + api.query.orderDir);\r\n} else if (api.query.orderBy) {\r\n api.url = api.url.replace('&order=code%2Cname', '');\r\n api.url = api.url.replace('&orderBy=' + api.query.orderBy + '&orderDir=', '&order=' + api.query.orderBy);\r\n} else {\r\n api.url = api.url.replace('&orderBy=&orderDir=', '');\r\n}\r\n\r\nreturn api;",
|
||||||
|
},
|
||||||
|
headerToolbar: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
icon: 'fa fa-plus',
|
||||||
|
level: 'default',
|
||||||
|
align: 'right',
|
||||||
|
label: '添加',
|
||||||
|
className: 'm-l-xs',
|
||||||
|
id: 'u:f4a47bb1a6d3',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '添加任课教师',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
name: 'code',
|
||||||
|
label: '账号',
|
||||||
|
mode: 'normal',
|
||||||
|
required: true,
|
||||||
|
id: 'u:bda0263ab8b8',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
name: 'name',
|
||||||
|
label: '姓名',
|
||||||
|
mode: 'normal',
|
||||||
|
required: true,
|
||||||
|
id: 'u:36976961498d',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-password',
|
||||||
|
name: 'password',
|
||||||
|
label: '密码',
|
||||||
|
mode: 'normal',
|
||||||
|
required: true,
|
||||||
|
id: 'u:ec15585cc409',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-password',
|
||||||
|
name: 'new_password',
|
||||||
|
label: '确认密码',
|
||||||
|
mode: 'normal',
|
||||||
|
required: true,
|
||||||
|
id: 'u:e364b38586a8',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'rest/rpc/create_user',
|
||||||
|
data: {
|
||||||
|
code: '$code',
|
||||||
|
name: '$name',
|
||||||
|
password: '$password',
|
||||||
|
new_password: '$new_password',
|
||||||
|
role: 'teacher',
|
||||||
|
orgs_id: '$centre_id',
|
||||||
|
},
|
||||||
|
requestAdaptor: '',
|
||||||
|
dataType: 'json',
|
||||||
|
headers: { Prefer: 'params=single-object' },
|
||||||
|
},
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
rule: 'this.password === this.new_password',
|
||||||
|
message: '两次密码输入不一致,请重新输入',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:9b27303ee8c7',
|
||||||
|
actions: [
|
||||||
|
{ type: 'submit', label: '提交', primary: true },
|
||||||
|
],
|
||||||
|
feat: 'Insert',
|
||||||
|
dsType: 'api',
|
||||||
|
onEvent: {
|
||||||
|
submitSucc: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
componentId: 'u:de2533791a72',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'reload',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
id: 'u:feafc93d557c',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'cancel',
|
||||||
|
label: '取消',
|
||||||
|
id: 'u:836089a67684',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'confirm',
|
||||||
|
label: '确定',
|
||||||
|
primary: true,
|
||||||
|
id: 'u:51adce35589e',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
actionType: 'dialog',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
align: 'right',
|
||||||
|
label: '导入',
|
||||||
|
icon: 'fa fa-upload',
|
||||||
|
level: 'warning',
|
||||||
|
id: 'u:25df91a187d4',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '教师导入',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'input-excel',
|
||||||
|
name: 'teachers',
|
||||||
|
label: '',
|
||||||
|
mode: 'normal',
|
||||||
|
id: 'u:5f0eca8a64fc',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-table',
|
||||||
|
name: 'teachers',
|
||||||
|
label: '',
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
label: '账号',
|
||||||
|
name: '账号',
|
||||||
|
placeholder: '-',
|
||||||
|
quickEdit: {
|
||||||
|
mode: 'inline',
|
||||||
|
id: 'u:e92d65ada484',
|
||||||
|
},
|
||||||
|
id: 'u:67eb5050eb4d',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '姓名',
|
||||||
|
name: '姓名',
|
||||||
|
placeholder: '-',
|
||||||
|
quickEdit: {
|
||||||
|
mode: 'inline',
|
||||||
|
id: 'u:2d4bdf8c7035',
|
||||||
|
},
|
||||||
|
id: 'u:74137b900acf',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
mode: 'normal',
|
||||||
|
visibleOn: 'this.teachers',
|
||||||
|
strictMode: true,
|
||||||
|
removable: true,
|
||||||
|
editable: false,
|
||||||
|
id: 'u:d73c846629ed',
|
||||||
|
clearValueOnHidden: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'rest/rpc/create_user',
|
||||||
|
data: {
|
||||||
|
orgs_id: '${centre_id}',
|
||||||
|
teachers: '${teachers}',
|
||||||
|
},
|
||||||
|
requestAdaptor:
|
||||||
|
"return {\r\n ...api,\r\n data: api.data.teachers.map(item => {\r\n return {\r\n name: item.姓名,\r\n code: item.账号,\r\n role: 'teacher',\r\n orgs_id: api.data.orgs_id\r\n }\r\n })\r\n}",
|
||||||
|
dataType: 'json',
|
||||||
|
headers: { Prefer: 'params=single-object' },
|
||||||
|
},
|
||||||
|
id: 'u:e60b2ab481ec',
|
||||||
|
actions: [
|
||||||
|
{ type: 'submit', label: '提交', primary: true },
|
||||||
|
],
|
||||||
|
feat: 'Insert',
|
||||||
|
dsType: 'api',
|
||||||
|
labelAlign: 'left',
|
||||||
|
onEvent: {
|
||||||
|
submitSucc: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
componentId: 'u:de2533791a72',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'reload',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
size: 'lg',
|
||||||
|
actionType: 'dialog',
|
||||||
|
id: 'u:249cb4918177',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'cancel',
|
||||||
|
label: '取消',
|
||||||
|
id: 'u:2d7cd1af378c',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'confirm',
|
||||||
|
label: '确定',
|
||||||
|
primary: true,
|
||||||
|
id: 'u:2dca052d9127',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'export-excel',
|
||||||
|
align: 'right',
|
||||||
|
label: '导出',
|
||||||
|
icon: 'fa fa-download',
|
||||||
|
level: 'primary',
|
||||||
|
api: 'rest/users?select=*,user_orgs(orgs(id))&role=eq.teacher&user_orgs.orgs.id=eq.$centre_id&order=code',
|
||||||
|
filename: '任课教师',
|
||||||
|
exportColumns: [
|
||||||
|
{ label: '账号', name: 'code' },
|
||||||
|
{ name: 'name', label: '姓名' },
|
||||||
|
],
|
||||||
|
id: 'u:e2ad66d916a5',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
syncLocation: false,
|
||||||
|
perPageAvailable: [10, 20, 30, 40, 50],
|
||||||
|
footerToolbar: [
|
||||||
|
{ type: 'pagination' },
|
||||||
|
{ type: 'switch-per-page' },
|
||||||
|
{ type: 'statistics' },
|
||||||
|
],
|
||||||
|
perPageField: 'perPage',
|
||||||
|
pageField: 'page',
|
||||||
|
title: '',
|
||||||
|
initApi: '',
|
||||||
|
bodyClassName: '',
|
||||||
|
id: 'u:de2533791a72',
|
||||||
|
affixHeader: true,
|
||||||
|
placeholder: '-',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
messages: {},
|
||||||
|
title: '',
|
||||||
|
id: 'u:1d83fac554fc',
|
||||||
|
definitions: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
export { schema };
|
||||||
485
src/pages/schema/centre/basic/team.schema.ts
Normal file
485
src/pages/schema/centre/basic/team.schema.ts
Normal file
@@ -0,0 +1,485 @@
|
|||||||
|
const schema = {
|
||||||
|
type: 'page',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'crud',
|
||||||
|
messages: {},
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/teams?select=*,team_members(users(id,code,name))&organization_id=eq.$centre_id&order=code',
|
||||||
|
data: {
|
||||||
|
page: '$page',
|
||||||
|
perPage: '$perPage',
|
||||||
|
},
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload.data,\r\n items: payload.data.items.map(item=> {\r\n return {\r\n ...item,\r\n selected_members: item.team_members.map(x => x.users.id)\r\n }\r\n })\r\n}\r\n',
|
||||||
|
},
|
||||||
|
headerToolbar: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
icon: 'fa fa-plus',
|
||||||
|
level: 'primary',
|
||||||
|
align: 'right',
|
||||||
|
label: '添加',
|
||||||
|
className: 'm-l-xs',
|
||||||
|
id: 'u:3c4c79023e6d',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '添加教学团队',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
name: 'code',
|
||||||
|
label: '编号',
|
||||||
|
mode: 'normal',
|
||||||
|
required: true,
|
||||||
|
id: 'u:9c6265d6605a',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
name: 'name',
|
||||||
|
label: '名称',
|
||||||
|
mode: 'normal',
|
||||||
|
required: true,
|
||||||
|
id: 'u:fb25ddbf9ea3',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-rich-text',
|
||||||
|
name: 'intro',
|
||||||
|
label: '描述',
|
||||||
|
mode: 'normal',
|
||||||
|
required: false,
|
||||||
|
options: {
|
||||||
|
menubar: false,
|
||||||
|
},
|
||||||
|
id: 'u:c88442289c84',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'rest/teams',
|
||||||
|
data: {
|
||||||
|
organization_id: '$centre_id',
|
||||||
|
code: '$code',
|
||||||
|
name: '$name',
|
||||||
|
intro: '$intro',
|
||||||
|
},
|
||||||
|
dataType: 'json',
|
||||||
|
},
|
||||||
|
id: 'u:5e5757012047',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'submit',
|
||||||
|
label: '提交',
|
||||||
|
primary: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
feat: 'Insert',
|
||||||
|
dsType: 'api',
|
||||||
|
onEvent: {
|
||||||
|
submitSucc: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
componentId: 'u:6b104aa599d9',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'reload',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
id: 'u:f020a946e699',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'cancel',
|
||||||
|
label: '取消',
|
||||||
|
id: 'u:d93f54d6db83',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'confirm',
|
||||||
|
label: '确定',
|
||||||
|
primary: true,
|
||||||
|
id: 'u:cc9454abf750',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
syncLocation: false,
|
||||||
|
perPageAvailable: [9, 27, 54],
|
||||||
|
footerToolbar: [
|
||||||
|
{
|
||||||
|
type: 'pagination',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'switch-per-page',
|
||||||
|
tpl: '内容',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
perPageField: 'perPage',
|
||||||
|
pageField: 'page',
|
||||||
|
bulkActions: [],
|
||||||
|
itemActions: [],
|
||||||
|
mode: 'cards',
|
||||||
|
card: {
|
||||||
|
type: 'card',
|
||||||
|
header: {
|
||||||
|
title: '$name',
|
||||||
|
subTitle: '$code',
|
||||||
|
},
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'tpl',
|
||||||
|
tpl: '${intro|raw}',
|
||||||
|
id: 'u:e89fc74f9f0a',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'each',
|
||||||
|
name: 'team_members',
|
||||||
|
placeholder: '未添加团队成员',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
type: 'plain',
|
||||||
|
tpl: '${users.name}',
|
||||||
|
inline: true,
|
||||||
|
className: 'm-l-sm',
|
||||||
|
id: 'u:53d23e452416',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '',
|
||||||
|
level: 'link',
|
||||||
|
icon: 'fa fa-times text-danger',
|
||||||
|
iconClassName: 'text-danger',
|
||||||
|
confirmText: '确认删除"${users.name}"?',
|
||||||
|
tooltip: '删除成员',
|
||||||
|
tooltipPlacement: 'top',
|
||||||
|
id: 'u:13cfdb0af771',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
outputVar: 'responseResult',
|
||||||
|
actionType: 'ajax',
|
||||||
|
options: {},
|
||||||
|
api: {
|
||||||
|
url: 'rest/team_members?team_id=eq.${id}&teacher_id=eq.${users.id}',
|
||||||
|
method: 'delete',
|
||||||
|
requestAdaptor: '',
|
||||||
|
adaptor: '',
|
||||||
|
messages: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentId: 'u:6b104aa599d9',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'reload',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:c6b9bef8b674',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
label: '',
|
||||||
|
type: 'button',
|
||||||
|
icon: 'fa fa-edit text-info',
|
||||||
|
tooltip: '修改教学团队',
|
||||||
|
tooltipPlacement: 'top',
|
||||||
|
size: 'md',
|
||||||
|
id: 'u:15a30654e625',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
api: {
|
||||||
|
method: 'patch',
|
||||||
|
url: 'rest/teams/${id}',
|
||||||
|
data: {
|
||||||
|
code: '$code',
|
||||||
|
name: '$name',
|
||||||
|
intro: '$intro',
|
||||||
|
teacher_list: '{${teacher_list}}',
|
||||||
|
},
|
||||||
|
dataType: 'json',
|
||||||
|
},
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
label: '编号',
|
||||||
|
name: 'code',
|
||||||
|
required: true,
|
||||||
|
mode: 'normal',
|
||||||
|
id: 'u:21b2f1785596',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '名称',
|
||||||
|
type: 'input-text',
|
||||||
|
name: 'name',
|
||||||
|
required: true,
|
||||||
|
mode: 'normal',
|
||||||
|
id: 'u:765ddf946178',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '描述',
|
||||||
|
type: 'input-rich-text',
|
||||||
|
name: 'intro',
|
||||||
|
options: {
|
||||||
|
menubar: false,
|
||||||
|
},
|
||||||
|
mode: 'normal',
|
||||||
|
id: 'u:454ab08215fc',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:51ad45e350ee',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'submit',
|
||||||
|
label: '提交',
|
||||||
|
primary: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
feat: 'Insert',
|
||||||
|
dsType: 'api',
|
||||||
|
onEvent: {
|
||||||
|
submitSucc: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
componentId: 'u:6b104aa599d9',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'reload',
|
||||||
|
data: {},
|
||||||
|
dataMergeMode: 'override',
|
||||||
|
args: {
|
||||||
|
resetPage: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: 'dialog',
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
title: '修改教学团队',
|
||||||
|
id: 'u:071e18a84182',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'cancel',
|
||||||
|
label: '取消',
|
||||||
|
id: 'u:07f56791977b',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'confirm',
|
||||||
|
label: '确定',
|
||||||
|
primary: true,
|
||||||
|
id: 'u:5e08c0b4a2c2',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '',
|
||||||
|
icon: 'fa fa-trash text-danger',
|
||||||
|
confirmText: '确认删除"${name}(${code})"?',
|
||||||
|
iconClassName: 'text-danger',
|
||||||
|
tooltip: '删除教学团队',
|
||||||
|
tooltipPlacement: 'top',
|
||||||
|
size: 'md',
|
||||||
|
id: 'u:481d5762073e',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
outputVar: 'responseResult',
|
||||||
|
actionType: 'ajax',
|
||||||
|
options: {},
|
||||||
|
api: {
|
||||||
|
url: 'rest/teams?id=eq.${id}',
|
||||||
|
method: 'delete',
|
||||||
|
requestAdaptor: '',
|
||||||
|
adaptor: '',
|
||||||
|
messages: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentId: 'u:6b104aa599d9',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'reload',
|
||||||
|
args: {
|
||||||
|
resetPage: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '',
|
||||||
|
icon: 'fa fa-group text-success',
|
||||||
|
size: 'md',
|
||||||
|
tooltip: '添加成员',
|
||||||
|
tooltipPlacement: 'top',
|
||||||
|
id: 'u:8ab4c946e195',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
title: '添加成员',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'rest/team_members',
|
||||||
|
data: {
|
||||||
|
select: '$select',
|
||||||
|
team_id: '${id}',
|
||||||
|
},
|
||||||
|
dataType: 'json',
|
||||||
|
requestAdaptor:
|
||||||
|
"return {\r\n ...api,\r\n data: api.data.select.split(',').map(item => {\r\n return {\r\n team_id: api.data.team_id,\r\n teacher_id: item\r\n }\r\n })\r\n}",
|
||||||
|
},
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
label: '',
|
||||||
|
name: 'select',
|
||||||
|
required: true,
|
||||||
|
mode: 'normal',
|
||||||
|
checkAll: false,
|
||||||
|
defaultCheckAll: false,
|
||||||
|
checkAllLabel: '全选',
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/users?select=*,user_orgs(organization_id)&role=eq.teacher&user_orgs.organization_id=eq.${centre_id}&id=not.in.(${selected_members})&order=code',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n data: payload.data.items.map(x=> {\r\n return {\r\n label: x.name,\r\n value: x.id\r\n }\r\n })\r\n}',
|
||||||
|
},
|
||||||
|
multiple: true,
|
||||||
|
joinValues: true,
|
||||||
|
id: 'u:d8d80248a021',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:518d0cab0bb2',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'submit',
|
||||||
|
label: '提交',
|
||||||
|
primary: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
feat: 'Insert',
|
||||||
|
dsType: 'api',
|
||||||
|
onEvent: {
|
||||||
|
submitSucc: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
componentId: 'u:6b104aa599d9',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'reload',
|
||||||
|
args: {
|
||||||
|
resetPage: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: 'dialog',
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
id: 'u:ca9566592590',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'cancel',
|
||||||
|
label: '取消',
|
||||||
|
id: 'u:537639203d7b',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'confirm',
|
||||||
|
label: '确定',
|
||||||
|
primary: true,
|
||||||
|
id: 'u:bdee93cc8455',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:c2cda94e1dbb',
|
||||||
|
},
|
||||||
|
placeholder: '暂无数据',
|
||||||
|
columnsCount: 3,
|
||||||
|
defaultParams: {
|
||||||
|
perPage: 9,
|
||||||
|
},
|
||||||
|
affixHeader: true,
|
||||||
|
id: 'u:6b104aa599d9',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
messages: {},
|
||||||
|
title: '',
|
||||||
|
id: 'u:418dc967756c',
|
||||||
|
};
|
||||||
|
|
||||||
|
export { schema };
|
||||||
592
src/pages/schema/centre/chart/evaluation.schema.ts
Normal file
592
src/pages/schema/centre/chart/evaluation.schema.ts
Normal file
@@ -0,0 +1,592 @@
|
|||||||
|
const schema = {
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
wrapWithPanel: false,
|
||||||
|
submitOnChange: true,
|
||||||
|
reload: '',
|
||||||
|
messages: {},
|
||||||
|
target:
|
||||||
|
'teacher2?semesterSelect=${semesterSelect}&course_id=${course_id}&parent_id=${parent_id},teacher1?semesterSelect=${semesterSelect}&course_id=${course_id}',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'group',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
label: '学期',
|
||||||
|
name: 'semesterSelect',
|
||||||
|
mode: 'inline',
|
||||||
|
size: 'lg',
|
||||||
|
clearable: false,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/semesters',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: payload.data.items.map(item => {\r\n return {\r\n label: `${item.name}(${item.code})`,\r\n value: item.id\r\n }\r\n })\r\n}',
|
||||||
|
},
|
||||||
|
checkAll: false,
|
||||||
|
searchable: true,
|
||||||
|
selectFirst: false,
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
label: '课程',
|
||||||
|
name: 'course_id',
|
||||||
|
mode: 'inline',
|
||||||
|
size: 'md',
|
||||||
|
clearable: false,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/courses?organization_id=eq.${centre_id}&semester_id=eq.${semesterSelect}&order=code',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: payload.data.items.length > 0 && payload.data.items.map(item => {\r\n return {\r\n label: `${item.name}(${item.code})`,\r\n value: item.id\r\n }\r\n })\r\n}',
|
||||||
|
sendOn: 'this.semesterSelect',
|
||||||
|
},
|
||||||
|
checkAll: false,
|
||||||
|
searchable: true,
|
||||||
|
selectFirst: false,
|
||||||
|
visibleOn: '',
|
||||||
|
clearValueOnHidden: false,
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
className: 'm-l-sm',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'group',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
label: '一级指标',
|
||||||
|
name: 'parent_id',
|
||||||
|
mode: 'inline',
|
||||||
|
size: 'md',
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/teaching_evaluation_items?organization_id=eq.${centre_id}&semester_id=eq.${semesterSelect}&parent=is.null&order=order',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: {\r\n ...payload.data,\r\n items: payload.data.items.map(item => {\r\n return {\r\n label: item.name,\r\n value: item.id\r\n }\r\n })\r\n }\r\n}',
|
||||||
|
sendOn: 'this.course_id',
|
||||||
|
},
|
||||||
|
checkAll: false,
|
||||||
|
searchable: true,
|
||||||
|
selectFirst: false,
|
||||||
|
visibleOn: 'this.course_id',
|
||||||
|
clearValueOnHidden: true,
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'grid',
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'flex',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
type: 'wrapper',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'chart',
|
||||||
|
config: {
|
||||||
|
title: [{ text: '教师统计(一级指标)' }],
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
data: '${series_data}',
|
||||||
|
type: 'radar',
|
||||||
|
emphasis: { lineStyle: { width: 4 } },
|
||||||
|
tooltip: { trigger: 'item' },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
tooltip: { trigger: 'axis' },
|
||||||
|
legend: {
|
||||||
|
type: 'scroll',
|
||||||
|
orient: 'vertical',
|
||||||
|
right: 10,
|
||||||
|
top: 20,
|
||||||
|
bottom: 20,
|
||||||
|
data: '${legend}',
|
||||||
|
},
|
||||||
|
radar: [
|
||||||
|
{
|
||||||
|
indicator: '${items}',
|
||||||
|
radius: 200,
|
||||||
|
startAngle: 90,
|
||||||
|
splitNumber: 5,
|
||||||
|
name: {
|
||||||
|
textStyle: {
|
||||||
|
color: '#fff',
|
||||||
|
backgroundColor: '#666',
|
||||||
|
borderRadius: 3,
|
||||||
|
padding: [3, 5],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
center: ['35%', '55%'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
toolbox: {
|
||||||
|
show: true,
|
||||||
|
feature: {
|
||||||
|
dataView: {
|
||||||
|
show: true,
|
||||||
|
title: '数据视图',
|
||||||
|
lang: ['数据视图', '关闭', '刷新'],
|
||||||
|
},
|
||||||
|
saveAsImage: {
|
||||||
|
show: true,
|
||||||
|
title: '保存为图片',
|
||||||
|
type: 'png',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
left: 170,
|
||||||
|
top: -2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
_mode: '2',
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'rest/rpc/evaluation_stats_teacher',
|
||||||
|
adaptor:
|
||||||
|
'let legend_set = new Set()\r\n\r\npayload.data.rows && payload.data.rows.forEach(item => {\r\n if(item.teacher_id) {\r\n legend_set.add(item.teacher_name.concat("(", item.teacher_id, ")"));\r\n } else {\r\n legend_set.add(\'未指定\');\r\n }\r\n})\r\n\r\nlet legend = Array.from(legend_set)\r\n\r\nlet series_data = legend\r\n ? legend.map(legend => {\r\n return {\r\n value: payload.data.rows.filter(\r\n item => item.teacher_id ? item.teacher_name.concat("(", item.teacher_id, ")") === legend : legend === \'未指定\'\r\n ).map(item => item.score),\r\n name: legend,\r\n symbol: "rect",\r\n symbolSize: 12,\r\n lineStyle: {\r\n type: "dashed"\r\n }\r\n }\r\n })\r\n : []\r\n\r\nreturn {\r\n ...payload,\r\n data: {\r\n ...payload.data,\r\n items: payload.data.items\r\n ? payload.data.items.sort(\r\n (a, b) => a.id - b.id\r\n ).map(item => {\r\n return {\r\n text: item.name,\r\n max: 5\r\n }\r\n })\r\n : [],\r\n legend: legend,\r\n series_data: series_data\r\n }\r\n}\r\n',
|
||||||
|
sendOn: 'this.course_id',
|
||||||
|
data: {
|
||||||
|
course_id: '${course_id}',
|
||||||
|
organization_id: '${centre_id}',
|
||||||
|
},
|
||||||
|
requestAdaptor: '',
|
||||||
|
},
|
||||||
|
dataFilter: '',
|
||||||
|
height: 480,
|
||||||
|
name: 'teacher1',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 'xs',
|
||||||
|
className: 'bg-white',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
direction: 'column',
|
||||||
|
justify: 'start',
|
||||||
|
alignItems: 'stretch',
|
||||||
|
className: '',
|
||||||
|
__mode: true,
|
||||||
|
style: {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'flex',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
type: 'wrapper',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'chart',
|
||||||
|
config: {
|
||||||
|
title: [{ text: '教师统计(二级指标)' }],
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
data: '${series_data}',
|
||||||
|
type: 'radar',
|
||||||
|
emphasis: { lineStyle: { width: 4 } },
|
||||||
|
tooltip: { trigger: 'item' },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
tooltip: { trigger: 'axis' },
|
||||||
|
legend: {
|
||||||
|
type: 'scroll',
|
||||||
|
orient: 'vertical',
|
||||||
|
right: 10,
|
||||||
|
top: 20,
|
||||||
|
bottom: 20,
|
||||||
|
data: '${legend}',
|
||||||
|
},
|
||||||
|
radar: [
|
||||||
|
{
|
||||||
|
indicator: '${items}',
|
||||||
|
radius: 200,
|
||||||
|
startAngle: 90,
|
||||||
|
splitNumber: 5,
|
||||||
|
name: {
|
||||||
|
textStyle: {
|
||||||
|
color: '#fff',
|
||||||
|
backgroundColor: '#666',
|
||||||
|
borderRadius: 3,
|
||||||
|
padding: [3, 5],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
center: ['35%', '55%'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
toolbox: {
|
||||||
|
show: true,
|
||||||
|
feature: {
|
||||||
|
dataView: {
|
||||||
|
show: true,
|
||||||
|
title: '数据视图',
|
||||||
|
lang: ['数据视图', '关闭', '刷新'],
|
||||||
|
},
|
||||||
|
saveAsImage: {
|
||||||
|
show: true,
|
||||||
|
title: '保存为图片',
|
||||||
|
type: 'png',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
left: 170,
|
||||||
|
top: -2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
_mode: '2',
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'rest/rpc/evaluation_stats_teacher',
|
||||||
|
adaptor:
|
||||||
|
'let legend_set = new Set()\r\n\r\npayload.data.rows && payload.data.rows.forEach(item => {\r\n if(item.teacher_id) {\r\n legend_set.add(item.teacher_name.concat("(", item.teacher_id, ")"));\r\n } else {\r\n legend_set.add(\'未指定\');\r\n }\r\n})\r\n\r\nlet legend = Array.from(legend_set)\r\n\r\nlet series_data = legend\r\n ? legend.map(legend => {\r\n return {\r\n value: payload.data.rows.filter(\r\n item => item.teacher_id ? item.teacher_name.concat("(", item.teacher_id, ")") === legend : legend === \'未指定\'\r\n ).map(item => item.score),\r\n name: legend,\r\n symbol: "rect",\r\n symbolSize: 12,\r\n lineStyle: {\r\n type: "dashed"\r\n }\r\n }\r\n })\r\n : []\r\n\r\nreturn {\r\n ...payload,\r\n data: {\r\n ...payload.data,\r\n items: payload.data.items\r\n ? payload.data.items.sort(\r\n (a, b) => a.id - b.id\r\n ).map(item => {\r\n return {\r\n text: item.name,\r\n max: 5\r\n }\r\n })\r\n : [],\r\n legend: legend,\r\n series_data: series_data\r\n }\r\n}\r\n',
|
||||||
|
sendOn: 'this.parent_id',
|
||||||
|
data: {
|
||||||
|
course_id: '${course_id}',
|
||||||
|
organization_id: '${centre_id}',
|
||||||
|
parent: '${parent_id}',
|
||||||
|
},
|
||||||
|
requestAdaptor: '',
|
||||||
|
},
|
||||||
|
dataFilter: '',
|
||||||
|
height: 480,
|
||||||
|
name: 'teacher2',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 'xs',
|
||||||
|
className: 'bg-white',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
direction: 'column',
|
||||||
|
justify: 'start',
|
||||||
|
alignItems: 'stretch',
|
||||||
|
className: '',
|
||||||
|
style: {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ type: 'divider', lineStyle: 'solid' },
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
wrapWithPanel: false,
|
||||||
|
submitOnChange: true,
|
||||||
|
reload: '',
|
||||||
|
messages: {},
|
||||||
|
target:
|
||||||
|
'location2?semesterSelect=${semesterSelect}&course_id=${course_id}&group_id=${group_id}&parent_id=${parent_id},location1?semesterSelect=${semesterSelect}&course_id=${course_id}&group_id=${group_id}',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'group',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
label: '学期',
|
||||||
|
name: 'semesterSelect',
|
||||||
|
mode: 'inline',
|
||||||
|
size: 'lg',
|
||||||
|
clearable: false,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/semesters?order=is_open.desc,since.desc',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: payload.data.items.map(item => {\r\n return {\r\n label: `${item.name}(${item.code})`,\r\n value: item.id\r\n }\r\n })\r\n}',
|
||||||
|
},
|
||||||
|
checkAll: false,
|
||||||
|
searchable: true,
|
||||||
|
selectFirst: false,
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
label: '课程',
|
||||||
|
name: 'course_id',
|
||||||
|
mode: 'inline',
|
||||||
|
size: 'md',
|
||||||
|
clearable: false,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/courses?organization_id=eq.${centre_id}&semester_id=eq.${semesterSelect}&order=code',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: payload.data.items.length > 0 && payload.data.items.map(item => {\r\n return {\r\n label: `${item.name}(${item.code})`,\r\n value: item.id\r\n }\r\n })\r\n}',
|
||||||
|
sendOn: 'this.semesterSelect',
|
||||||
|
},
|
||||||
|
checkAll: false,
|
||||||
|
searchable: true,
|
||||||
|
selectFirst: false,
|
||||||
|
visibleOn: '',
|
||||||
|
clearValueOnHidden: false,
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
className: 'm-l-sm',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
label: '场地组合',
|
||||||
|
name: 'group_id',
|
||||||
|
mode: 'inline',
|
||||||
|
size: 'lg',
|
||||||
|
clearable: true,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/locations?organization_id=eq.${centre_id}&type=eq.laboratory&is_valid=is.true&order=code',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: payload.data.items.length > 0 && payload.data.items.map(item => {\r\n return {\r\n label: item.name,\r\n value: item.id\r\n }\r\n })\r\n}',
|
||||||
|
},
|
||||||
|
checkAll: true,
|
||||||
|
searchable: true,
|
||||||
|
selectFirst: false,
|
||||||
|
visibleOn: '',
|
||||||
|
clearValueOnHidden: false,
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
className: 'm-l-sm',
|
||||||
|
multiple: true,
|
||||||
|
joinValues: true,
|
||||||
|
valuesNoWrap: false,
|
||||||
|
defaultCheckAll: false,
|
||||||
|
checkAllLabel: '全选',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'group',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
label: '一级指标',
|
||||||
|
name: 'parent_id',
|
||||||
|
mode: 'inline',
|
||||||
|
size: 'md',
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/teaching_evaluation_items?organization_id=eq.${centre_id}&semester_id=eq.${semesterSelect}&parent=is.null&order=order',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: {\r\n ...payload.data,\r\n items: payload.data.items.map(item => {\r\n return {\r\n label: item.name,\r\n value: item.id\r\n }\r\n })\r\n }\r\n}',
|
||||||
|
sendOn: 'this.course_id',
|
||||||
|
},
|
||||||
|
checkAll: false,
|
||||||
|
searchable: true,
|
||||||
|
selectFirst: false,
|
||||||
|
visibleOn: 'this.course_id',
|
||||||
|
clearValueOnHidden: true,
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'grid',
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'flex',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
type: 'wrapper',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'chart',
|
||||||
|
config: {
|
||||||
|
title: [{ text: '场地统计(一级指标)' }],
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
data: '${series_data}',
|
||||||
|
type: 'radar',
|
||||||
|
emphasis: { lineStyle: { width: 4 } },
|
||||||
|
tooltip: { trigger: 'item' },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
tooltip: { trigger: 'axis' },
|
||||||
|
legend: {
|
||||||
|
type: 'scroll',
|
||||||
|
orient: 'vertical',
|
||||||
|
right: 10,
|
||||||
|
top: 20,
|
||||||
|
bottom: 20,
|
||||||
|
data: '${legend}',
|
||||||
|
},
|
||||||
|
radar: [
|
||||||
|
{
|
||||||
|
indicator: '${items}',
|
||||||
|
radius: 200,
|
||||||
|
startAngle: 90,
|
||||||
|
splitNumber: 5,
|
||||||
|
name: {
|
||||||
|
textStyle: {
|
||||||
|
color: '#fff',
|
||||||
|
backgroundColor: '#666',
|
||||||
|
borderRadius: 3,
|
||||||
|
padding: [3, 5],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
center: ['35%', '55%'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
toolbox: {
|
||||||
|
show: true,
|
||||||
|
feature: {
|
||||||
|
dataView: {
|
||||||
|
show: true,
|
||||||
|
title: '数据视图',
|
||||||
|
lang: ['数据视图', '关闭', '刷新'],
|
||||||
|
},
|
||||||
|
saveAsImage: {
|
||||||
|
show: true,
|
||||||
|
title: '保存为图片',
|
||||||
|
type: 'png',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
left: 170,
|
||||||
|
top: -2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
_mode: '2',
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'rest/rpc/evaluation_stats_location',
|
||||||
|
adaptor:
|
||||||
|
'let legend_set = new Set()\r\n\r\npayload.data.rows && payload.data.rows.forEach(item => {\r\n legend_set.add(item.location_name)\r\n})\r\n\r\nlet legend = Array.from(legend_set)\r\n\r\nlet series_data = legend\r\n ? legend.map(legend => {\r\n return {\r\n value: payload.data.rows.filter(\r\n item => item.location_name === legend\r\n ).map(item => item.score),\r\n name: legend,\r\n symbol: "rect",\r\n symbolSize: 12,\r\n lineStyle: {\r\n type: "dashed"\r\n }\r\n }\r\n })\r\n : []\r\n\r\nreturn {\r\n ...payload,\r\n data: {\r\n ...payload.data,\r\n items: payload.data.items\r\n ? payload.data.items.sort(\r\n (a, b) => a.id - b.id\r\n ).map(item => {\r\n return {\r\n text: item.name,\r\n max: 5\r\n }\r\n })\r\n : [],\r\n legend: legend,\r\n series_data: series_data\r\n }\r\n}\r\n',
|
||||||
|
sendOn: 'this.course_id',
|
||||||
|
data: {
|
||||||
|
course_id: '${course_id}',
|
||||||
|
organization_id: '${centre_id}',
|
||||||
|
group: '${group_id}',
|
||||||
|
},
|
||||||
|
requestAdaptor:
|
||||||
|
"if (api.body.group === '') {\r\n delete api.body.group\r\n}\r\n\r\nreturn {\r\n ...api\r\n}",
|
||||||
|
},
|
||||||
|
dataFilter: '',
|
||||||
|
height: 480,
|
||||||
|
name: 'location1',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 'xs',
|
||||||
|
className: 'bg-white',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
direction: 'column',
|
||||||
|
justify: 'start',
|
||||||
|
alignItems: 'stretch',
|
||||||
|
className: '',
|
||||||
|
__mode: true,
|
||||||
|
style: {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'flex',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
type: 'wrapper',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'chart',
|
||||||
|
config: {
|
||||||
|
title: [{ text: '场地统计(二级指标)' }],
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
data: '${series_data}',
|
||||||
|
type: 'radar',
|
||||||
|
emphasis: { lineStyle: { width: 4 } },
|
||||||
|
tooltip: { trigger: 'item' },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
tooltip: { trigger: 'axis' },
|
||||||
|
legend: {
|
||||||
|
type: 'scroll',
|
||||||
|
orient: 'vertical',
|
||||||
|
right: 10,
|
||||||
|
top: 20,
|
||||||
|
bottom: 20,
|
||||||
|
data: '${legend}',
|
||||||
|
},
|
||||||
|
radar: [
|
||||||
|
{
|
||||||
|
indicator: '${items}',
|
||||||
|
radius: 200,
|
||||||
|
startAngle: 90,
|
||||||
|
splitNumber: 5,
|
||||||
|
name: {
|
||||||
|
textStyle: {
|
||||||
|
color: '#fff',
|
||||||
|
backgroundColor: '#666',
|
||||||
|
borderRadius: 3,
|
||||||
|
padding: [3, 5],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
center: ['35%', '55%'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
toolbox: {
|
||||||
|
show: true,
|
||||||
|
feature: {
|
||||||
|
dataView: {
|
||||||
|
show: true,
|
||||||
|
title: '数据视图',
|
||||||
|
lang: ['数据视图', '关闭', '刷新'],
|
||||||
|
},
|
||||||
|
saveAsImage: {
|
||||||
|
show: true,
|
||||||
|
title: '保存为图片',
|
||||||
|
type: 'png',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
left: 170,
|
||||||
|
top: -2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
_mode: '2',
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'rest/rpc/evaluation_stats_location',
|
||||||
|
adaptor:
|
||||||
|
'let legend_set = new Set()\r\n\r\npayload.data.rows && payload.data.rows.forEach(item => {\r\n legend_set.add(item.location_name)\r\n})\r\n\r\nlet legend = Array.from(legend_set)\r\n\r\nlet series_data = legend\r\n ? legend.map(legend => {\r\n return {\r\n value: payload.data.rows.filter(\r\n item => item.location_name === legend\r\n ).map(item => item.score),\r\n name: legend,\r\n symbol: "rect",\r\n symbolSize: 12,\r\n lineStyle: {\r\n type: "dashed"\r\n }\r\n }\r\n })\r\n : []\r\n\r\nreturn {\r\n ...payload,\r\n data: {\r\n ...payload.data,\r\n items: payload.data.items\r\n ? payload.data.items.sort(\r\n (a, b) => a.id - b.id\r\n ).map(item => {\r\n return {\r\n text: item.name,\r\n max: 5\r\n }\r\n })\r\n : [],\r\n legend: legend,\r\n series_data: series_data\r\n }\r\n}\r\n',
|
||||||
|
sendOn: 'this.parent_id',
|
||||||
|
data: {
|
||||||
|
course_id: '${course_id}',
|
||||||
|
organization_id: '${centre_id}',
|
||||||
|
parent: '${parent_id}',
|
||||||
|
group: '${group_id}',
|
||||||
|
},
|
||||||
|
requestAdaptor:
|
||||||
|
"if (api.body.group === '') {\r\n delete api.body.group\r\n}\r\n\r\nreturn {\r\n ...api\r\n}",
|
||||||
|
},
|
||||||
|
dataFilter: '',
|
||||||
|
height: 480,
|
||||||
|
name: 'location2',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 'xs',
|
||||||
|
className: 'bg-white',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
direction: 'column',
|
||||||
|
justify: 'start',
|
||||||
|
alignItems: 'stretch',
|
||||||
|
className: '',
|
||||||
|
style: {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: 'page',
|
||||||
|
};
|
||||||
|
|
||||||
|
export { schema };
|
||||||
209
src/pages/schema/centre/chart/grade.schema.ts
Normal file
209
src/pages/schema/centre/chart/grade.schema.ts
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
const schema = {
|
||||||
|
type: 'page',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
submitOnChange: true,
|
||||||
|
reload: 'statistic?course_id=$course_id&org_id=$org_id',
|
||||||
|
wrapWithPanel: false,
|
||||||
|
messages: {
|
||||||
|
fetchFailed: '初始化失败',
|
||||||
|
saveSuccess: '统计成功',
|
||||||
|
saveFailed: '保存失败',
|
||||||
|
},
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
label: '学期',
|
||||||
|
type: 'select',
|
||||||
|
name: 'semesterSelect',
|
||||||
|
mode: 'inline',
|
||||||
|
clearable: false,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/semesters?order=is_open.desc,since.desc',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: payload.data.items.map(item => {\r\n return {\r\n label: `${item.name}(${item.code})`,\r\n value: item.id\r\n }\r\n })\r\n}',
|
||||||
|
},
|
||||||
|
checkAll: false,
|
||||||
|
size: 'lg',
|
||||||
|
searchable: true,
|
||||||
|
selectFirst: false,
|
||||||
|
id: 'u:b1122bff1df9',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
label: '课程',
|
||||||
|
name: 'course_id',
|
||||||
|
mode: 'inline',
|
||||||
|
clearable: false,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/courses?organization_id=eq.$centre_id&semester_id=eq.$semesterSelect&order=code',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: payload.data.items.length > 0 && payload.data.items.map(item => {\r\n return {\r\n label: `${item.name}(${item.code})`,\r\n value: item.id\r\n }\r\n })\r\n}',
|
||||||
|
sendOn: 'this.semesterSelect',
|
||||||
|
},
|
||||||
|
checkAll: false,
|
||||||
|
size: 'lg',
|
||||||
|
searchable: true,
|
||||||
|
selectFirst: false,
|
||||||
|
visibleOn: '',
|
||||||
|
clearValueOnHidden: false,
|
||||||
|
id: 'u:2e2358141406',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
label: '班级',
|
||||||
|
name: 'org_id',
|
||||||
|
mode: 'inline',
|
||||||
|
clearable: true,
|
||||||
|
size: 'lg',
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/orgs?select=*,course2orgs!inner(*)&path=cd.root&course2orgs.course_id=eq.$course_id&type=in.(school,centre,faculty,class,reelectclass)&order=code',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: {\r\n ...payload.data,\r\n items: payload.data.items.map(item => ({\r\n label: item.name,\r\n value: item.id\r\n }))\r\n }\r\n}',
|
||||||
|
sendOn: 'this.course_id',
|
||||||
|
requestAdaptor: '',
|
||||||
|
messages: {},
|
||||||
|
},
|
||||||
|
searchable: true,
|
||||||
|
visibleOn: 'this.course_id',
|
||||||
|
clearValueOnHidden: true,
|
||||||
|
multiple: true,
|
||||||
|
joinValues: true,
|
||||||
|
delimiter: ',',
|
||||||
|
cascade: false,
|
||||||
|
initiallyOpen: false,
|
||||||
|
unfoldedLevel: 2,
|
||||||
|
onlyChildren: true,
|
||||||
|
withChildren: false,
|
||||||
|
extractValue: true,
|
||||||
|
id: 'u:84b51bcafda6',
|
||||||
|
autoCheckChildren: true,
|
||||||
|
enableNodePath: false,
|
||||||
|
showIcon: true,
|
||||||
|
checkAll: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'control',
|
||||||
|
label: '',
|
||||||
|
remark: null,
|
||||||
|
mode: 'inline',
|
||||||
|
visibleOn: 'this.is_cursem && this.course_id',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
level: 'primary',
|
||||||
|
actionType: 'ajax',
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'rest/rpc/calculate_grade',
|
||||||
|
data: {
|
||||||
|
course_id: '$course_id',
|
||||||
|
org_id: '$org_id',
|
||||||
|
},
|
||||||
|
requestAdaptor:
|
||||||
|
'const { course_id, org_id } = api.data\r\n\r\nif (org_id) {\r\n return {\r\n ...api\r\n }\r\n} else {\r\n return {\r\n ...api,\r\n data: { course_id }\r\n }\r\n}',
|
||||||
|
},
|
||||||
|
reload: 'statistic',
|
||||||
|
messages: {},
|
||||||
|
label: '统计',
|
||||||
|
id: 'u:a147092cff8f',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:4944fd7962d5',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'service',
|
||||||
|
messages: {},
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/semesters?id=eq.$semesterSelect',
|
||||||
|
sendOn: 'this.semesterSelect',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: {\r\n is_cursem: payload.data.items.length > 0 ? payload.data.items[0].is_open : false\r\n }\r\n}',
|
||||||
|
},
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'hidden',
|
||||||
|
name: 'is_cursem',
|
||||||
|
id: 'u:39ca4db8501a',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:3e13ab87d15b',
|
||||||
|
dsType: 'api',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:970b1b98cc6a',
|
||||||
|
feat: 'Insert',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'crud',
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'rest/rpc/grade_stat',
|
||||||
|
data: {
|
||||||
|
page: '$page',
|
||||||
|
course_id: '$course_id',
|
||||||
|
perpage: '$perPage',
|
||||||
|
org_id: '$org_id',
|
||||||
|
},
|
||||||
|
adaptor: '',
|
||||||
|
requestAdaptor:
|
||||||
|
'const { course_id, org_id, page, perpage } = api.data\r\n\r\nif (course_id && org_id) {\r\n return {\r\n ...api\r\n }\r\n} else if (course_id) {\r\n return {\r\n ...api,\r\n data: { course_id, page, perpage }\r\n }\r\n} else {\r\n return {\r\n ...api,\r\n data: {}\r\n }\r\n}',
|
||||||
|
dataType: 'form',
|
||||||
|
sendOn: '',
|
||||||
|
},
|
||||||
|
columns: [],
|
||||||
|
messages: {},
|
||||||
|
syncLocation: false,
|
||||||
|
pageField: 'page',
|
||||||
|
perPageField: 'perPage',
|
||||||
|
headerToolbar: [
|
||||||
|
{
|
||||||
|
type: 'export-excel',
|
||||||
|
label: '全量导出 Excel',
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'rest/rpc/grade_stat',
|
||||||
|
data: {
|
||||||
|
course_id: '$course_id',
|
||||||
|
org_id: '$org_id',
|
||||||
|
},
|
||||||
|
dataType: 'form',
|
||||||
|
requestAdaptor:
|
||||||
|
'const { course_id, org_id } = api.data\r\n\r\nif (course_id && org_id) {\r\n return {\r\n ...api\r\n }\r\n} else if (course_id) {\r\n return {\r\n ...api,\r\n data: { course_id }\r\n }\r\n} else {\r\n return {\r\n ...api,\r\n data: {}\r\n }\r\n}',
|
||||||
|
},
|
||||||
|
filename: '$filename',
|
||||||
|
id: 'u:8d80c123da31',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
footerToolbar: [
|
||||||
|
{
|
||||||
|
type: 'pagination',
|
||||||
|
tpl: '内容',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'switch-per-page',
|
||||||
|
tpl: '内容',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
name: 'statistic',
|
||||||
|
title: '',
|
||||||
|
bodyClassName: 'common-height',
|
||||||
|
body: [],
|
||||||
|
toolbar: [],
|
||||||
|
alwaysShowPagination: false,
|
||||||
|
perPageAvailable: [10, 20, 30, 40, 50],
|
||||||
|
affixHeader: false,
|
||||||
|
id: 'u:ec1754a6f5a9',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
title: '',
|
||||||
|
messages: {},
|
||||||
|
id: 'u:e3bc67e03bea',
|
||||||
|
};
|
||||||
|
|
||||||
|
export { schema };
|
||||||
411
src/pages/schema/centre/chart/workload.schema.ts
Normal file
411
src/pages/schema/centre/chart/workload.schema.ts
Normal file
@@ -0,0 +1,411 @@
|
|||||||
|
const schema = {
|
||||||
|
type: 'page',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'grid',
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
md: 8,
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'chart',
|
||||||
|
config: {
|
||||||
|
title: [
|
||||||
|
{
|
||||||
|
text: '实验项目开课次数统计',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
data: '$yAxis_les',
|
||||||
|
type: 'pie',
|
||||||
|
name: '项目',
|
||||||
|
radius: '55%',
|
||||||
|
center: ['40%', '50%'],
|
||||||
|
emphasis: {
|
||||||
|
itemStyle: {
|
||||||
|
shadowBlur: 10,
|
||||||
|
shadowOffsetX: 0,
|
||||||
|
shadowColor: 'rgba(0, 0, 0, 0.5)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'item',
|
||||||
|
formatter: '{a} <br/>{b} : {c} ({d}%)',
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
type: 'scroll',
|
||||||
|
orient: 'vertical',
|
||||||
|
top: 20,
|
||||||
|
bottom: 20,
|
||||||
|
data: '$xAxis_exp',
|
||||||
|
right: 10,
|
||||||
|
},
|
||||||
|
toolbox: {
|
||||||
|
show: true,
|
||||||
|
feature: {
|
||||||
|
dataView: {
|
||||||
|
show: true,
|
||||||
|
title: '数据视图',
|
||||||
|
lang: ['数据视图', '关闭', '刷新'],
|
||||||
|
},
|
||||||
|
saveAsImage: {
|
||||||
|
show: true,
|
||||||
|
title: '保存为图片',
|
||||||
|
type: 'png',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
left: 190,
|
||||||
|
top: -2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
_mode: '2',
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/schedules?select=*,projects:projects!schedule_project_id_fkey(id,name)&semester_id=eq.${semesterSelect}&teacher_id=in.(${teacherSelect})',
|
||||||
|
requestAdaptor:
|
||||||
|
"api.url = api.url.replace('&teacher_id=in.%28%29', '')\r\n\r\nreturn api",
|
||||||
|
adaptor:
|
||||||
|
'let xAxis_exp = []\r\nlet yAxis_les = []\r\npayload.data.items.forEach(item => {\r\n const index_exp = xAxis_exp.findIndex(i => i === item.projects.name)\r\n if (index_exp === -1) {\r\n xAxis_exp.push(item.projects.name)\r\n const index_exp = xAxis_exp.findIndex(i => i === item.projects.name)\r\n yAxis_les[index_exp] = {\r\n name: item.projects.name,\r\n value: 1\r\n }\r\n } else {\r\n yAxis_les[index_exp].value += 1\r\n }\r\n})\r\nreturn {\r\n ...payload,\r\n data: {\r\n xAxis_exp: xAxis_exp,\r\n yAxis_les: yAxis_les\r\n }\r\n}',
|
||||||
|
error: {
|
||||||
|
message: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
dataFilter: '',
|
||||||
|
height: 450,
|
||||||
|
name: 'chart1',
|
||||||
|
id: 'u:4f3d6cd9e92a',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:3a343388441f',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'chart',
|
||||||
|
config: {
|
||||||
|
title: [
|
||||||
|
{
|
||||||
|
text: '教师课堂次数统计',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
data: '$yAxis_les',
|
||||||
|
type: 'pie',
|
||||||
|
name: '教师',
|
||||||
|
radius: '55%',
|
||||||
|
center: ['40%', '50%'],
|
||||||
|
emphasis: {
|
||||||
|
itemStyle: {
|
||||||
|
shadowBlur: 10,
|
||||||
|
shadowOffsetX: 0,
|
||||||
|
shadowColor: 'rgba(0, 0, 0, 0.5)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'item',
|
||||||
|
formatter: '{a} <br/>{b} : {c} ({d}%)',
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
type: 'scroll',
|
||||||
|
orient: 'vertical',
|
||||||
|
right: 10,
|
||||||
|
top: 20,
|
||||||
|
bottom: 20,
|
||||||
|
data: '$xAxis_exp',
|
||||||
|
},
|
||||||
|
toolbox: {
|
||||||
|
show: true,
|
||||||
|
feature: {
|
||||||
|
dataView: {
|
||||||
|
show: true,
|
||||||
|
title: '数据视图',
|
||||||
|
lang: ['数据视图', '关闭', '刷新'],
|
||||||
|
},
|
||||||
|
saveAsImage: {
|
||||||
|
show: true,
|
||||||
|
title: '保存为图片',
|
||||||
|
type: 'png',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
left: 155,
|
||||||
|
top: -2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
_mode: '2',
|
||||||
|
dataFilter: '',
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/users?select=*,schedules:schedules!schedule_teacher_id_fkey(*,projects:projects!schedule_project_id_fkey(id,name))&role=eq.teacher&schedules.semester_id=eq.${semesterSelect}&id=in.(${teacherSelect})&order=code',
|
||||||
|
requestAdaptor:
|
||||||
|
"api.url = api.url.replace('&id=in.%28%29', '')\r\n\r\nreturn api",
|
||||||
|
adaptor:
|
||||||
|
'let xAxis_tch = []\r\nlet yAxis_les = []\r\npayload.data.items.forEach(payload_item => {\r\n let elected = 0\r\n xAxis_tch.push(payload_item.name)\r\n yAxis_les.push({\r\n name: payload_item.name,\r\n value: payload_item.schedules.length ? payload_item.schedules.length : 0\r\n })\r\n})\r\nreturn {\r\n ...payload,\r\n data: {\r\n xAxis_tch: xAxis_tch,\r\n yAxis_les: yAxis_les\r\n }\r\n}',
|
||||||
|
},
|
||||||
|
height: 450,
|
||||||
|
name: 'chart2',
|
||||||
|
id: 'u:ed31d767d8d5',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:989c40ed8233',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:63c06d3a12fc',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'divider',
|
||||||
|
lineStyle: 'solid',
|
||||||
|
id: 'u:b0c8cc501851',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'chart',
|
||||||
|
config: {
|
||||||
|
title: [
|
||||||
|
{
|
||||||
|
text: '实验项目相关人次统计',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
axisPointer: {
|
||||||
|
type: 'cross',
|
||||||
|
label: {
|
||||||
|
backgroundColor: '#283b56',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
data: ['可选人数', '已选人数', '签到人数', '未签到人数'],
|
||||||
|
},
|
||||||
|
xAxis: [
|
||||||
|
{
|
||||||
|
type: 'category',
|
||||||
|
data: '$xAxis_exp',
|
||||||
|
axisLabel: {
|
||||||
|
rotate: -10,
|
||||||
|
interval: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
yAxis: {
|
||||||
|
type: 'value',
|
||||||
|
name: '人数',
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
data: '$yAxis_unsel',
|
||||||
|
type: 'bar',
|
||||||
|
name: '可选人数',
|
||||||
|
barWidth: 20,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: '$yAxis_sel',
|
||||||
|
type: 'bar',
|
||||||
|
name: '已选人数',
|
||||||
|
barWidth: 20,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: '$yAxis_fin',
|
||||||
|
type: 'bar',
|
||||||
|
name: '签到人数',
|
||||||
|
barWidth: 10,
|
||||||
|
stack: '已选人数',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: '$yAxis_unfin',
|
||||||
|
type: 'bar',
|
||||||
|
name: '未签到人数',
|
||||||
|
barWidth: 10,
|
||||||
|
stack: '已选人数',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
toolbox: {
|
||||||
|
show: true,
|
||||||
|
feature: {
|
||||||
|
dataView: {
|
||||||
|
show: true,
|
||||||
|
title: '数据视图',
|
||||||
|
lang: ['数据视图', '关闭', '刷新'],
|
||||||
|
},
|
||||||
|
saveAsImage: {
|
||||||
|
show: true,
|
||||||
|
title: '保存为图片',
|
||||||
|
type: 'png',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
left: 190,
|
||||||
|
top: -2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
_mode: '2',
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/workload_stats?select=*,projects:projects!schedule_project_id_fkey(id,name)&semester_id=eq.$semesterSelect&teacher_id=in.(${teacherSelect})&organization_id=eq.$centre_id',
|
||||||
|
requestAdaptor:
|
||||||
|
"api.url = api.url.replace('&teacher_id=in.%28%29', '')\r\n\r\nreturn api",
|
||||||
|
adaptor:
|
||||||
|
'let xAxis_exp = []\r\nlet yAxis_sel = []\r\nlet yAxis_unsel = []\r\nlet yAxis_fin = []\r\nlet yAxis_unfin = []\r\n\r\npayload.data.items.forEach(item => {\r\n const index_exp = xAxis_exp.findIndex(i => i === item.projects.name)\r\n\r\n if (index_exp === -1) {\r\n xAxis_exp.push(item.projects.name)\r\n const index_exp = xAxis_exp.findIndex(i => i === item.projects.name)\r\n yAxis_sel[index_exp] = item.current_student_number\r\n yAxis_unsel[index_exp] = item.max_student_number - item.current_student_number\r\n yAxis_fin[index_exp] = item.finished_count\r\n yAxis_unfin[index_exp] = item.unfinished_count\r\n } else {\r\n yAxis_sel[index_exp] += item.current_student_number\r\n yAxis_unsel[index_exp] += (item.max_student_number - item.current_student_number)\r\n yAxis_fin[index_exp] += item.finished_count\r\n yAxis_unfin[index_exp] += item.unfinished_count\r\n }\r\n})\r\n\r\nreturn {\r\n ...payload,\r\n data: {\r\n xAxis_exp: xAxis_exp,\r\n yAxis_sel: yAxis_sel,\r\n yAxis_unsel: yAxis_unsel,\r\n yAxis_fin: yAxis_fin,\r\n yAxis_unfin: yAxis_unfin\r\n }\r\n}',
|
||||||
|
},
|
||||||
|
replaceChartOption: false,
|
||||||
|
dataFilter: '',
|
||||||
|
height: 450,
|
||||||
|
name: 'chart3',
|
||||||
|
id: 'u:5357767552e5',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'divider',
|
||||||
|
lineStyle: 'solid',
|
||||||
|
id: 'u:01c9e40a887d',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'chart',
|
||||||
|
config: {
|
||||||
|
title: [
|
||||||
|
{
|
||||||
|
text: '教师课堂相关人次统计',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
axisPointer: {
|
||||||
|
type: 'cross',
|
||||||
|
label: {
|
||||||
|
backgroundColor: '#283b56',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
data: ['已选人数', '签到人数', '未签到人数'],
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: 'value',
|
||||||
|
name: '人数',
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
data: '$yAxis_sel',
|
||||||
|
type: 'bar',
|
||||||
|
name: '已选人数',
|
||||||
|
barWidth: 20,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: '$yAxis_fin',
|
||||||
|
type: 'bar',
|
||||||
|
name: '签到人数',
|
||||||
|
barWidth: 10,
|
||||||
|
stack: '已选人数',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: '$yAxis_unfin',
|
||||||
|
type: 'bar',
|
||||||
|
name: '未签到人数',
|
||||||
|
barWidth: 10,
|
||||||
|
stack: '已选人数',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
xAxis: [
|
||||||
|
{
|
||||||
|
type: 'category',
|
||||||
|
data: '$xAxis_tch',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
toolbox: {
|
||||||
|
show: true,
|
||||||
|
feature: {
|
||||||
|
dataView: {
|
||||||
|
show: true,
|
||||||
|
title: '数据视图',
|
||||||
|
lang: ['数据视图', '关闭', '刷新'],
|
||||||
|
},
|
||||||
|
saveAsImage: {
|
||||||
|
show: true,
|
||||||
|
title: '保存为图片',
|
||||||
|
type: 'png',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
left: 190,
|
||||||
|
top: -2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
_mode: '2',
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/users?select=*,workload_stats:workload_stats!schedule_teacher_id_fkey(*,projects:projects!schedule_project_id_fkey(id,name))&role=eq.teacher&workload_stats.semester_id=eq.$semesterSelect&id=in.(${teacherSelect})&workload_stats.organization_id=eq.$centre_id&order=code',
|
||||||
|
requestAdaptor:
|
||||||
|
"api.url = api.url.replace('&id=in.%28%29', '')\r\n\r\nreturn api",
|
||||||
|
adaptor:
|
||||||
|
'let xAxis_tch = []\r\nlet yAxis_sel = []\r\nlet yAxis_fin = []\r\nlet yAxis_unfin = []\r\n\r\npayload.data.items.forEach(payload_item => {\r\n let elected = 0\r\n let finished = 0\r\n let unfinished = 0\r\n\r\n payload_item.workload_stats.length > 0 && payload_item.workload_stats.forEach(workload_item => {\r\n elected += workload_item.current_student_number\r\n finished += workload_item.finished_count\r\n unfinished += workload_item.unfinished_count\r\n })\r\n\r\n xAxis_tch.push(payload_item.name)\r\n yAxis_sel.push(elected)\r\n yAxis_fin.push(finished)\r\n yAxis_unfin.push(unfinished)\r\n})\r\n\r\nreturn {\r\n ...payload,\r\n data: {\r\n xAxis_tch: xAxis_tch,\r\n yAxis_sel: yAxis_sel,\r\n yAxis_fin: yAxis_fin,\r\n yAxis_unfin: yAxis_unfin\r\n }\r\n}',
|
||||||
|
},
|
||||||
|
replaceChartOption: false,
|
||||||
|
dataFilter: '',
|
||||||
|
height: 450,
|
||||||
|
name: 'chart4',
|
||||||
|
id: 'u:9c6e8236a44f',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'divider',
|
||||||
|
lineStyle: 'solid',
|
||||||
|
id: 'u:e448f96e6b83',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
toolbar: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
wrapWithPanel: false,
|
||||||
|
submitOnChange: true,
|
||||||
|
target: 'chart1,chart2,chart3,chart4',
|
||||||
|
canAccessSuperData: true,
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
label: '学期',
|
||||||
|
type: 'select',
|
||||||
|
name: 'semesterSelect',
|
||||||
|
mode: 'inline',
|
||||||
|
clearable: false,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/semesters?order=is_open.desc,since.desc',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: payload.data.items.map(item => {\r\n return {\r\n label: `${item.name}(${item.code})`,\r\n value: item.id\r\n }\r\n })\r\n}',
|
||||||
|
},
|
||||||
|
checkAll: false,
|
||||||
|
size: 'lg',
|
||||||
|
searchable: true,
|
||||||
|
selectFirst: false,
|
||||||
|
className: 'm',
|
||||||
|
id: 'u:bdeea7faf818',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '教师',
|
||||||
|
type: 'select',
|
||||||
|
name: 'teacherSelect',
|
||||||
|
mode: 'inline',
|
||||||
|
clearable: true,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/users?role=eq.teacher&order=name,code',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: payload.data.items.map(item => {\r\n return {\r\n label: `${item.name}(${item.code})`,\r\n value: item.id\r\n }\r\n })\r\n}',
|
||||||
|
},
|
||||||
|
checkAll: true,
|
||||||
|
size: 'lg',
|
||||||
|
searchable: true,
|
||||||
|
selectFirst: false,
|
||||||
|
multiple: true,
|
||||||
|
className: 'm',
|
||||||
|
id: 'u:bdeea7faf818',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:5003bb8ac5e6',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:b5376a388009',
|
||||||
|
};
|
||||||
|
|
||||||
|
export { schema };
|
||||||
148
src/pages/schema/centre/computing/dataset.schema.ts
Normal file
148
src/pages/schema/centre/computing/dataset.schema.ts
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
const schema = {
|
||||||
|
type: 'page',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'dataset-renderer',
|
||||||
|
name: 'storage',
|
||||||
|
bucket: 'dataset',
|
||||||
|
addFolder: {
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'dialog',
|
||||||
|
reload: 'storage',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '新建文件夹',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'storage/v1/object/dataset/$path/$name/.empty',
|
||||||
|
requestAdaptor:
|
||||||
|
"api.url = api.url.replace('//', '/');return api",
|
||||||
|
},
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
label: '文件夹名称',
|
||||||
|
name: 'name',
|
||||||
|
mode: 'normal',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
moveFile: {
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'dialog',
|
||||||
|
reload: 'storage',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '重命名',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'storage/v1/object/move',
|
||||||
|
data: {
|
||||||
|
bucketId: 'dataset',
|
||||||
|
sourceKey: '$sourceKey',
|
||||||
|
dest: '$dest',
|
||||||
|
path: '$path',
|
||||||
|
},
|
||||||
|
requestAdaptor:
|
||||||
|
"console.log(api)\r\nreturn {\r\n ...api,\r\n data: {\r\n bucketId: api.data.bucketId,\r\n sourceKey: api.data.sourceKey,\r\n destinationKey: api.data.path === '' ? api.data.dest : api.data.path + '/' + api.data.dest\r\n }\r\n}",
|
||||||
|
},
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
name: 'dest',
|
||||||
|
type: 'input-text',
|
||||||
|
label: '名称',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
delFile: {
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'ajax',
|
||||||
|
reload: 'storage',
|
||||||
|
label: false,
|
||||||
|
api: {
|
||||||
|
method: 'delete',
|
||||||
|
url: '/storage/v1/object/dataset',
|
||||||
|
data: {
|
||||||
|
prefixes: '$prefixes',
|
||||||
|
},
|
||||||
|
headers: {
|
||||||
|
post2rest: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
confirmText: '确认删除吗?',
|
||||||
|
},
|
||||||
|
delFiles: {
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'dialog',
|
||||||
|
reload: 'storage',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '批量删除文件',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
api: {
|
||||||
|
method: 'delete',
|
||||||
|
url: 'storage/v1/object/dataset',
|
||||||
|
data: { prefixes: '$prefixes', path: '$path' },
|
||||||
|
headers: { post2rest: false },
|
||||||
|
requestAdaptor:
|
||||||
|
"return {\r\n ...api,\r\n data: {\r\n prefixes: api.data.prefixes.map(item => api.data.path === '' ? item : api.data.path + '/' + item)\r\n }\r\n}",
|
||||||
|
},
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
name: 'prefixes',
|
||||||
|
type: 'checkboxes',
|
||||||
|
label: false,
|
||||||
|
inline: false,
|
||||||
|
checkAll: true,
|
||||||
|
joinValues: false,
|
||||||
|
extractValue: true,
|
||||||
|
required: true,
|
||||||
|
source: {
|
||||||
|
method: 'post',
|
||||||
|
url: '/storage/v1/object/list/dataset',
|
||||||
|
data: {
|
||||||
|
prefix: '$path',
|
||||||
|
sortBy: {
|
||||||
|
column: 'name',
|
||||||
|
order: 'asc',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: payload.data.filter(item => item.id && item.name.charAt(0) !== ".").map(item => {\r\n return {\r\n label: item.name,\r\n value: item.name\r\n }\r\n })\r\n}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
,
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export { schema };
|
||||||
667
src/pages/schema/centre/computing/docrecommend.schema.ts
Normal file
667
src/pages/schema/centre/computing/docrecommend.schema.ts
Normal file
@@ -0,0 +1,667 @@
|
|||||||
|
const schema = {
|
||||||
|
type: 'page',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'container',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
className: '',
|
||||||
|
submitOnChange: true,
|
||||||
|
reload: 'notebooks?author=$author&type=$type&publish_at=$publish_at',
|
||||||
|
wrapWithPanel: false,
|
||||||
|
canAccessSuperData: false,
|
||||||
|
mode: 'inline',
|
||||||
|
name: 'filter',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'group',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
mode: 'inline',
|
||||||
|
label: '作者',
|
||||||
|
name: 'author',
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/users?order=code',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: payload.data.items.map(item => {\r\n return {\r\n label: item.name + "(" + item.code + ")",\r\n value: "eq." + item.code\r\n }\r\n })\r\n}',
|
||||||
|
},
|
||||||
|
checkAll: false,
|
||||||
|
size: 'md',
|
||||||
|
searchable: true,
|
||||||
|
clearable: true,
|
||||||
|
className: 'm-l-sm',
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
id: 'u:f2ef198e2dcf',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
label: '类型',
|
||||||
|
name: 'type',
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/dicts?typecode=eq.028&order=id',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: payload.data.items.map(item => {\r\n return {\r\n label: item.dictvalue,\r\n value: "eq." + item.dictkey\r\n }\r\n })\r\n}',
|
||||||
|
},
|
||||||
|
mode: 'inline',
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
size: 'md',
|
||||||
|
clearable: true,
|
||||||
|
id: 'u:28cd5a8d0d4f',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-date-range',
|
||||||
|
name: 'publish_at',
|
||||||
|
mode: 'inline',
|
||||||
|
label: '发布日期',
|
||||||
|
clearable: true,
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
value: '',
|
||||||
|
format: 'YYYY-MM-DD',
|
||||||
|
ranges:
|
||||||
|
'yesterday,today,7daysago,prevweek,thismonth,prevmonth,prevquarter',
|
||||||
|
id: 'u:0b09573c1ed9',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:e19f8840c465',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:83f2045dc8aa',
|
||||||
|
feat: 'Insert',
|
||||||
|
},
|
||||||
|
{ type: 'divider', lineStyle: 'solid', id: 'u:b12bc5cfec5e' },
|
||||||
|
{
|
||||||
|
type: 'crud',
|
||||||
|
name: 'notebooks',
|
||||||
|
syncLocation: false,
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/notebooks?select=*,type:dicts!notebook_type_fkey(*),status:dicts!notebook_status_fkey(*)&name=like.*$keywords*&isprivate=is.false&author=$author&type=$type&order=publish_at.desc.nullslast',
|
||||||
|
data: {
|
||||||
|
page: '$page',
|
||||||
|
perPage: 8,
|
||||||
|
orderBy: '$orderBy',
|
||||||
|
orderDir: '$orderDir',
|
||||||
|
publish_at: '$publish_at',
|
||||||
|
},
|
||||||
|
requestAdaptor:
|
||||||
|
"if (api.query.author === '') api.url = api.url.replace('&author=', '')\r\n\r\nif (api.query.type === '') api.url = api.url.replace('&type=', '')\r\n\r\nif (api.body.publish_at === '') {\r\n api.url = api.url.replace('&publish_at=', '')\r\n} else {\r\n let date_former = api.body.publish_at && api.body.publish_at.split(',')[0]\r\n let date_latter = api.body.publish_at && api.body.publish_at.split(',')[1]\r\n\r\n if (date_former === date_latter) {\r\n api.url = api.url.replace(\r\n '&publish_at=' + date_former + '%2C' + date_latter,\r\n '&publish_at=gte.' + date_former + ' 00:00:00&publish_at=lte.' + date_former + ' 23:59:59'\r\n )\r\n } else {\r\n api.url = api.url.replace(\r\n '&publish_at=' + date_former + '%2C' + date_latter,\r\n '&publish_at=gte.' + date_former + ' 00:00:00&publish_at=lte.' + date_latter + ' 23:59:59'\r\n )\r\n }\r\n}\r\n\r\nif (api.query.orderBy && api.query.orderDir) {\r\n api.url = api.url.replace('order=publish_at.desc.nullslast', '');\r\n api.url = api.url.replace('&orderBy=' + api.query.orderBy + '&orderDir=' + api.query.orderDir, '&order=' + api.query.orderBy + '.' + api.query.orderDir);\r\n} else {\r\n api.url = api.url.replace('&orderBy=' + api.query.orderBy + '&orderDir=' + api.query.orderDir, '');\r\n}\r\n\r\nreturn api;",
|
||||||
|
},
|
||||||
|
footerToolbar: [
|
||||||
|
{ type: 'pagination' },
|
||||||
|
{ type: 'switch-per-page' },
|
||||||
|
{ type: 'statistics' },
|
||||||
|
],
|
||||||
|
perPageAvailable: [8,],
|
||||||
|
bulkActions: [],
|
||||||
|
itemActions: [],
|
||||||
|
id: 'u:46a2b5faa785',
|
||||||
|
filter: {
|
||||||
|
title: '',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
name: 'keywords',
|
||||||
|
label: '名称关键字',
|
||||||
|
id: 'u:a9a2048f6f68',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'submit',
|
||||||
|
label: '搜索',
|
||||||
|
actionType: 'submit',
|
||||||
|
id: 'u:decd16bff04d',
|
||||||
|
level: 'primary',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
reload: 'notebooks?keywords=$keywords',
|
||||||
|
canAccessSuperData: false,
|
||||||
|
wrapWithPanel: false,
|
||||||
|
autoFocus: false,
|
||||||
|
mode: 'inline',
|
||||||
|
id: 'u:1888123468b3',
|
||||||
|
feat: 'Insert',
|
||||||
|
},
|
||||||
|
messages: {},
|
||||||
|
card: {
|
||||||
|
type: 'card',
|
||||||
|
header: {
|
||||||
|
title: '',
|
||||||
|
subTitle: '',
|
||||||
|
avatar: '/olms/notebook/${pid}/cover.png',
|
||||||
|
desc: '',
|
||||||
|
},
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
name: 'name',
|
||||||
|
label: '',
|
||||||
|
type: 'text',
|
||||||
|
sortable: true,
|
||||||
|
id: 'u:02b589f37127',
|
||||||
|
inline: true,
|
||||||
|
tpl: '名称:${name}',
|
||||||
|
placeholder: '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'author',
|
||||||
|
label: '',
|
||||||
|
type: 'text',
|
||||||
|
sortable: true,
|
||||||
|
id: 'u:3c98eb214a1b',
|
||||||
|
inline: true,
|
||||||
|
tpl: '创建者:${author}'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-tag',
|
||||||
|
label: '',
|
||||||
|
name: 'tag',
|
||||||
|
id: 'u:7302818b79ff',
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/tags?order=name',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: payload.data.items.map((item) => {\r\n return {\r\n ...item,\r\n label: item.name,\r\n value: item.name,\r\n };\r\n }),\r\n};',
|
||||||
|
},
|
||||||
|
multiple: true,
|
||||||
|
joinValues: false,
|
||||||
|
extractValue: true,
|
||||||
|
mode: 'normal',
|
||||||
|
clearable: false,
|
||||||
|
creatable: true,
|
||||||
|
createBtnLabel: '新增标签',
|
||||||
|
addControls: [
|
||||||
|
{
|
||||||
|
label: '名称',
|
||||||
|
type: 'text',
|
||||||
|
name: 'name',
|
||||||
|
value: '',
|
||||||
|
required: true,
|
||||||
|
mode: 'normal',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
addApi: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'rest/tags',
|
||||||
|
data: { name: '${name}' },
|
||||||
|
dataType: 'json',
|
||||||
|
},
|
||||||
|
editable: false,
|
||||||
|
editControls: [
|
||||||
|
{
|
||||||
|
label: '名称',
|
||||||
|
type: 'text',
|
||||||
|
name: 'name',
|
||||||
|
value: '',
|
||||||
|
required: true,
|
||||||
|
mode: 'normal',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
editApi: {
|
||||||
|
method: 'patch',
|
||||||
|
url: 'rest/tags?id=eq.${id}',
|
||||||
|
data: { name: '${name}' },
|
||||||
|
dataType: 'json',
|
||||||
|
},
|
||||||
|
removable: true,
|
||||||
|
deleteApi: { method: 'delete', url: 'rest/tags?id=eq.${id}' },
|
||||||
|
optionsTip: '最近您使用的标签',
|
||||||
|
className: 'm-b-sm m-t-sm',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'description',
|
||||||
|
label: '描述',
|
||||||
|
type: 'text',
|
||||||
|
sortable: true,
|
||||||
|
id: 'u:67cf5873f23e',
|
||||||
|
inline: true,
|
||||||
|
hidden: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'type.dictvalue',
|
||||||
|
label: '类型',
|
||||||
|
type: 'text',
|
||||||
|
sortable: true,
|
||||||
|
id: 'u:c3eb052e801c',
|
||||||
|
inline: true,
|
||||||
|
hidden: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'publish_at',
|
||||||
|
label: '发布日期',
|
||||||
|
type: 'date',
|
||||||
|
format: 'YYYY-MM-DD',
|
||||||
|
sortable: true,
|
||||||
|
id: 'u:fdb56224ba1b',
|
||||||
|
hidden: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
name: 'tag',
|
||||||
|
label: '标签',
|
||||||
|
placeholder: '-',
|
||||||
|
id: 'u:d3e2a072de3c',
|
||||||
|
inline: true,
|
||||||
|
hidden: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'mapping',
|
||||||
|
map: {
|
||||||
|
false: '<span class="label label-danger">否</span>',
|
||||||
|
true: '<span class="label label-success">是</span>',
|
||||||
|
},
|
||||||
|
label: '首页展示',
|
||||||
|
name: 'isrecommend',
|
||||||
|
sortable: true,
|
||||||
|
id: 'u:c717e7e057a9',
|
||||||
|
hidden: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'recommendOrder',
|
||||||
|
label: '展示次序',
|
||||||
|
type: 'text',
|
||||||
|
sortable: true,
|
||||||
|
id: 'u:77fb26a7f92e',
|
||||||
|
inline: true,
|
||||||
|
hidden: true,
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// type: 'button-group',
|
||||||
|
// buttons: [
|
||||||
|
// {
|
||||||
|
// type: 'button',
|
||||||
|
// actionType: 'dialog',
|
||||||
|
// dialog: {
|
||||||
|
// title: '修改标签',
|
||||||
|
// body: [
|
||||||
|
// {
|
||||||
|
// type: 'form',
|
||||||
|
// title: '表单',
|
||||||
|
// api: {
|
||||||
|
// method: 'patch',
|
||||||
|
// url: 'rest/notebooks?id=eq.${id}',
|
||||||
|
// data: { tag: '${tag}' },
|
||||||
|
// dataType: 'json',
|
||||||
|
// },
|
||||||
|
// body: [
|
||||||
|
// {
|
||||||
|
// label: '标签',
|
||||||
|
// type: 'select',
|
||||||
|
// name: 'tag',
|
||||||
|
// checkAll: true,
|
||||||
|
// source: {
|
||||||
|
// method: 'get',
|
||||||
|
// url: 'rest/tags?order=name',
|
||||||
|
// adaptor:
|
||||||
|
// 'return {\r\n ...payload,\r\n data: payload.data.items.map((item) => {\r\n return {\r\n ...item,\r\n label: item.name,\r\n value: item.name,\r\n };\r\n }),\r\n};',
|
||||||
|
// },
|
||||||
|
// multiple: true,
|
||||||
|
// joinValues: false,
|
||||||
|
// extractValue: true,
|
||||||
|
// mode: 'normal',
|
||||||
|
// clearable: true,
|
||||||
|
// creatable: true,
|
||||||
|
// createBtnLabel: '新增标签',
|
||||||
|
// addControls: [
|
||||||
|
// {
|
||||||
|
// label: '名称',
|
||||||
|
// type: 'text',
|
||||||
|
// name: 'name',
|
||||||
|
// value: '',
|
||||||
|
// required: true,
|
||||||
|
// mode: 'normal',
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// addApi: {
|
||||||
|
// method: 'post',
|
||||||
|
// url: 'rest/tags',
|
||||||
|
// data: { name: '${name}' },
|
||||||
|
// dataType: 'json',
|
||||||
|
// },
|
||||||
|
// editable: true,
|
||||||
|
// editControls: [
|
||||||
|
// {
|
||||||
|
// label: '名称',
|
||||||
|
// type: 'text',
|
||||||
|
// name: 'name',
|
||||||
|
// value: '',
|
||||||
|
// required: true,
|
||||||
|
// mode: 'normal',
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// editApi: {
|
||||||
|
// method: 'patch',
|
||||||
|
// url: 'rest/tags?id=eq.${id}',
|
||||||
|
// data: { name: '${name}' },
|
||||||
|
// dataType: 'json',
|
||||||
|
// },
|
||||||
|
// removable: true,
|
||||||
|
// deleteApi: {
|
||||||
|
// method: 'delete',
|
||||||
|
// url: 'rest/tags?id=eq.${id}',
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// type: 'dialog',
|
||||||
|
// closeOnEsc: true,
|
||||||
|
// showCloseButton: true,
|
||||||
|
// },
|
||||||
|
// level: 'link',
|
||||||
|
// icon: 'fa fa-pencil text-info',
|
||||||
|
// size: 'md',
|
||||||
|
// tooltip: '修改标签',
|
||||||
|
// tooltipPlacement: 'top',
|
||||||
|
// iconClassName: 'pull-left',
|
||||||
|
// className: 'p-r-none p-l-none',
|
||||||
|
// id: 'u:39235263c3cb',
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// type: 'button',
|
||||||
|
// label: '',
|
||||||
|
// level: 'link',
|
||||||
|
// size: 'md',
|
||||||
|
// icon: 'fa fa-eye text-warning',
|
||||||
|
// iconClassName: 'pull-left',
|
||||||
|
// actionType: 'dialog',
|
||||||
|
// tooltip: '预览',
|
||||||
|
// tooltipPlacement: 'top',
|
||||||
|
// className: 'p-r-none p-l-none',
|
||||||
|
// dialog: {
|
||||||
|
// title: '预览',
|
||||||
|
// body: [
|
||||||
|
// {
|
||||||
|
// type: 'form',
|
||||||
|
// title: '表单',
|
||||||
|
// body: [
|
||||||
|
// {
|
||||||
|
// type: 'formula',
|
||||||
|
// name: 'iframeSrc',
|
||||||
|
// formula:
|
||||||
|
// '"http://192.168.71.19"+ "/notebook/" + pid + "/" + post',
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// type: 'iframe',
|
||||||
|
// src: '${iframeSrc}',
|
||||||
|
// height: '700px',
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// type: 'dialog',
|
||||||
|
// closeOnEsc: false,
|
||||||
|
// closeOnOutside: false,
|
||||||
|
// showCloseButton: true,
|
||||||
|
// size: 'xl',
|
||||||
|
// actions: [],
|
||||||
|
// },
|
||||||
|
// id: 'u:1aa082ee65f0',
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// type: 'button',
|
||||||
|
// label: '',
|
||||||
|
// actionType: 'dialog',
|
||||||
|
// size: 'md',
|
||||||
|
// tooltip: '首页展示',
|
||||||
|
// tooltipPlacement: 'top',
|
||||||
|
// iconClassName: 'pull-left',
|
||||||
|
// className: 'p-r-none p-l-none',
|
||||||
|
// icon: 'fa fa-thumbs-up text-info',
|
||||||
|
// level: 'link',
|
||||||
|
// visibleOn: 'this.type.dictkey === "notebook"',
|
||||||
|
// dialog: {
|
||||||
|
// type: 'dialog',
|
||||||
|
// title: '首页展示',
|
||||||
|
// body: [
|
||||||
|
// {
|
||||||
|
// type: 'form',
|
||||||
|
// title: '表单',
|
||||||
|
// api: {
|
||||||
|
// method: 'patch',
|
||||||
|
// url: 'rest/notebooks/$id',
|
||||||
|
// data: { '&': '$$' },
|
||||||
|
// requestAdaptor:
|
||||||
|
// 'if (api.data.recommendOrder) api.data.isrecommend = true;\r\nelse api.data.isrecommend = false;\r\n\r\nreturn api;',
|
||||||
|
// },
|
||||||
|
// reload: 'notebooks',
|
||||||
|
// body: [
|
||||||
|
// {
|
||||||
|
// type: 'select',
|
||||||
|
// label: '序号',
|
||||||
|
// name: 'recommendOrder',
|
||||||
|
// clearable: true,
|
||||||
|
// options: [
|
||||||
|
// { label: '1', value: 1 },
|
||||||
|
// { label: '2', value: 2 },
|
||||||
|
// { label: '3', value: 3 },
|
||||||
|
// { label: '4', value: 4 },
|
||||||
|
// { label: '5', value: 5 },
|
||||||
|
// { label: '6', value: 6 },
|
||||||
|
// { label: '7', value: 7 },
|
||||||
|
// { label: '8', value: 8 },
|
||||||
|
// ],
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// closeOnEsc: true,
|
||||||
|
// showCloseButton: true,
|
||||||
|
// closeOnOutside: false,
|
||||||
|
// size: 'sm',
|
||||||
|
// },
|
||||||
|
// id: 'u:98e68e904df9',
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// type: 'button',
|
||||||
|
// label: '',
|
||||||
|
// level: 'link',
|
||||||
|
// icon: 'fa fa-times text-danger',
|
||||||
|
// size: 'md',
|
||||||
|
// tooltip: '删除',
|
||||||
|
// tooltipPlacement: 'top',
|
||||||
|
// iconClassName: 'pull-left',
|
||||||
|
// className: 'p-r-none p-l-none',
|
||||||
|
// actionType: 'ajax',
|
||||||
|
// api: { method: 'post', url: 'nb/cancel_notebook/$id/$pid' },
|
||||||
|
// id: 'u:713ccf6aa5fc',
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// id: 'u:2408808996c7',
|
||||||
|
// label: '',
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
type: 'button-group',
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '预览',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
actionType: 'hidden',
|
||||||
|
componentId: 'u:5fe9a2ffdbe1',
|
||||||
|
ignoreError: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentId: 'u:16d9090a3803',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'show',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentId: 'my_service1',
|
||||||
|
actionType: 'setValue',
|
||||||
|
args: { value: '${event.data}' },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
level: 'light',
|
||||||
|
size: 'sm',
|
||||||
|
id: 'u:1aa082ee65f0',
|
||||||
|
themeCss: {
|
||||||
|
className: {
|
||||||
|
'border:default': {
|
||||||
|
'top-border-style': 'solid',
|
||||||
|
'left-border-style': 'solid',
|
||||||
|
'right-border-style': 'solid',
|
||||||
|
'bottom-border-style': 'solid',
|
||||||
|
'top-border-width': 'none',
|
||||||
|
'left-border-width': 'none',
|
||||||
|
'right-border-width': 'none',
|
||||||
|
'bottom-border-width': 'none',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// type: 'button',
|
||||||
|
// label: '预览',
|
||||||
|
// onEvent: {
|
||||||
|
// click: {
|
||||||
|
// actions: [
|
||||||
|
// {
|
||||||
|
// actionType: 'hidden',
|
||||||
|
// componentId: 'u:5fe9a2ffdbe1',
|
||||||
|
// ignoreError: false,
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// componentId: 'u:16d9090a3803',
|
||||||
|
// ignoreError: false,
|
||||||
|
// actionType: 'show',
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// componentId: 'my_service1',
|
||||||
|
// actionType: 'setValue',
|
||||||
|
// args: { value: '${event.data}' },
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// id: 'u:60093cd4c74f',
|
||||||
|
// level: 'light',
|
||||||
|
// size: 'xs',
|
||||||
|
// },
|
||||||
|
],
|
||||||
|
actions: [],
|
||||||
|
id: 'u:8f1fae00368b',
|
||||||
|
imageClassName: 'w-full h-sm',
|
||||||
|
avatarClassName: 'w-full',
|
||||||
|
},
|
||||||
|
mode: 'cards',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
style: {
|
||||||
|
position: 'relative',
|
||||||
|
display: 'flex',
|
||||||
|
inset: 'auto',
|
||||||
|
flexWrap: 'nowrap',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'flex-start',
|
||||||
|
},
|
||||||
|
size: 'none',
|
||||||
|
wrapperBody: false,
|
||||||
|
id: 'u:5fe9a2ffdbe1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'container',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '返回',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
componentId: 'u:5fe9a2ffdbe1',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'show',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentId: 'u:16d9090a3803',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'hidden',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
id: 'u:a0f4fc5477c0',
|
||||||
|
themeCss: {
|
||||||
|
className: {
|
||||||
|
'border:default': {
|
||||||
|
'top-border-width': 'none',
|
||||||
|
'left-border-width': 'none',
|
||||||
|
'right-border-width': 'none',
|
||||||
|
'bottom-border-width': 'none',
|
||||||
|
},
|
||||||
|
'font:default': {
|
||||||
|
color: '#36586b',
|
||||||
|
fontWeight: '500',
|
||||||
|
fontSize: '24px',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
size: 'lg',
|
||||||
|
block: false,
|
||||||
|
level: 'link',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'page',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'service',
|
||||||
|
data: {
|
||||||
|
pid: '490f5308c4bd486fb2225f1e70198768',
|
||||||
|
post: '00_实践总览.ipynb',
|
||||||
|
},
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'formula',
|
||||||
|
name: 'iframeSrc',
|
||||||
|
formula:
|
||||||
|
'location.origin + "/notebook/" + this.pid + "/" + this.post',
|
||||||
|
id: 'u:479855e2164e',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'iframe',
|
||||||
|
src: '${iframeSrc}/?token=$user.token',
|
||||||
|
height: '700px',
|
||||||
|
id: 'u:d2171dd0883e',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'my_service1',
|
||||||
|
dsType: 'api',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:d57881a83b7f',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
style: {
|
||||||
|
position: 'relative',
|
||||||
|
display: 'flex',
|
||||||
|
inset: 'auto',
|
||||||
|
flexWrap: 'nowrap',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'flex-start',
|
||||||
|
},
|
||||||
|
size: 'none',
|
||||||
|
wrapperBody: false,
|
||||||
|
id: 'u:16d9090a3803',
|
||||||
|
isFixedHeight: false,
|
||||||
|
isFixedWidth: false,
|
||||||
|
hidden: true,
|
||||||
|
visible: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:4b1560f3b2db',
|
||||||
|
asideResizor: false,
|
||||||
|
pullRefresh: { disabled: true },
|
||||||
|
definitions: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
export { schema };
|
||||||
295
src/pages/schema/centre/computing/homework.schema.ts
Normal file
295
src/pages/schema/centre/computing/homework.schema.ts
Normal file
@@ -0,0 +1,295 @@
|
|||||||
|
const schema = {
|
||||||
|
type: 'page',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
className: '',
|
||||||
|
submitOnChange: true,
|
||||||
|
submitOnInit: true,
|
||||||
|
reload:
|
||||||
|
'manage_loc?semesterSelect=$semesterSelect&course_id=$course_id&project_id=$project_id&organization_id=$org_id',
|
||||||
|
wrapWithPanel: false,
|
||||||
|
canAccessSuperData: false,
|
||||||
|
mode: 'inline',
|
||||||
|
name: 'filter',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'group',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
label: '学期',
|
||||||
|
name: 'semesterSelect',
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/semesters?order=is_open.desc,since.desc',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: payload.data.items.map((item) => {\r\n return {\r\n label: item.name,\r\n value: item.id,\r\n };\r\n }),\r\n};',
|
||||||
|
},
|
||||||
|
submitOnChange: true,
|
||||||
|
mode: 'inline',
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
size: 'md',
|
||||||
|
searchable: true,
|
||||||
|
selectFirst: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
mode: 'inline',
|
||||||
|
label: '课程',
|
||||||
|
name: 'course_id',
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/courses?organization_id=eq.$centre_id&semester_id=eq.$semesterSelect&order=code',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: payload.data.items.map(item => {\r\n return {\r\n label: `${item.name}(${item.code})`,\r\n value: "eq.".concat(item.id)\r\n }\r\n })\r\n}',
|
||||||
|
},
|
||||||
|
size: 'md',
|
||||||
|
searchable: true,
|
||||||
|
selectFirst: true,
|
||||||
|
className: 'm-l-sm',
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
label: '项目',
|
||||||
|
name: 'project_id',
|
||||||
|
mode: 'inline',
|
||||||
|
clearable: true,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/course2projects?select=projects(id,name)&projects.organization_id=eq.${centre_id}&projects.semester_id=eq.${semesterSelect}&projects.free_schedule=eq.false&course_id=${course_id}',
|
||||||
|
adaptor:
|
||||||
|
'let projects = [];\r\npayload.data.items.filter(item => item.projects !== null).forEach(item => {\r\n if (projects.findIndex(x => x.value === item.projects.id) === -1) {\r\n projects.push({\r\n label: item.projects.name,\r\n value: "eq.".concat(item.projects.id)\r\n });\r\n }\r\n});\r\nreturn {\r\n data: projects\r\n}',
|
||||||
|
requestAdaptor:
|
||||||
|
"if (api.query.course_id === '') {\r\n api.url = api.url.replace('&course_id=', '');\r\n}\r\n\r\nreturn api;",
|
||||||
|
sendOn: 'this.course_id',
|
||||||
|
},
|
||||||
|
checkAll: false,
|
||||||
|
size: 'md',
|
||||||
|
searchable: true,
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
className: 'm-l-sm',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
label: '班级',
|
||||||
|
name: 'org_id',
|
||||||
|
mode: 'inline',
|
||||||
|
size: 'md',
|
||||||
|
clearable: true,
|
||||||
|
searchable: true,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/orgs?select=*,course2orgs!inner(*)&type=eq.class&path=cd.root.1&course2orgs.course_id=${course_id}&order=name,code',
|
||||||
|
requestAdaptor:
|
||||||
|
'if (api.query.course2orgs.course_id === "eq.") {\r\n api.url = api.url.replace("&course2orgs[course_id]=eq.", "")\r\n}\r\nif (api.query.course2orgs.course_id === "eq.undefined") {\r\n api.url = api.url.replace("&course2orgs[course_id]=eq.undefined", "")\r\n}',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n data: payload.data.items.map(item => {\r\n return {\r\n label: item.name,\r\n value: "eq." + item.id\r\n }\r\n })\r\n}',
|
||||||
|
sendOn: 'this.course_id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'divider',
|
||||||
|
lineStyle: 'solid',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'crud',
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/users_ex1?semester_id=eq.$semesterSelect&name=like.*$keywords*&role=eq.student&course_id=$course_id&project_id=$project_id&organization_id=$organization_id&organization_type=eq.class&order=name,code',
|
||||||
|
data: {
|
||||||
|
page: '$page',
|
||||||
|
perPage: '$perPage',
|
||||||
|
orderBy: '$orderBy',
|
||||||
|
orderDir: '$orderDir',
|
||||||
|
},
|
||||||
|
adaptor: '',
|
||||||
|
requestAdaptor:
|
||||||
|
"api.url = api.url.replace('&semesterSelect=', '&semester_id=eq.')\r\napi.url = api.url.replace('&keywords=' + api.query.keywords, '')\r\n\r\nif (api.query.project_id === '') {\r\n api.url = api.url.replace('&project_id=', '')\r\n}\r\n\r\nif (api.query.organization_id === '') {\r\n api.url = api.url.replace('&organization_id=', '')\r\n}\r\n\r\nif (api.query.id === '') {\r\n api.url = api.url.replace('&id=', '')\r\n}\r\n\r\nif (api.query.orderBy && api.query.orderDir) {\r\n api.url = api.url.replace('&order=name%2Ccode', '');\r\n api.url = api.url.replace('&orderBy=' + api.query.orderBy + '&orderDir=' + api.query.orderDir, '&order=' + api.query.orderBy + '.' + api.query.orderDir);\r\n} else {\r\n api.url = api.url.replace('&orderBy=' + api.query.orderBy + '&orderDir=' + api.query.orderDir, '');\r\n}\r\n\r\nreturn {\r\n ...api\r\n}",
|
||||||
|
sendOn: 'this.course_id',
|
||||||
|
},
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '学生',
|
||||||
|
name: 'name',
|
||||||
|
placeholder: '-',
|
||||||
|
sortable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '学号',
|
||||||
|
name: 'code',
|
||||||
|
placeholder: '-',
|
||||||
|
sortable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '班级',
|
||||||
|
name: 'organization_name',
|
||||||
|
placeholder: '-',
|
||||||
|
sortable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '课程',
|
||||||
|
name: 'course_name',
|
||||||
|
placeholder: '-',
|
||||||
|
sortable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '项目',
|
||||||
|
name: 'project_name',
|
||||||
|
placeholder: '-',
|
||||||
|
sortable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '作业',
|
||||||
|
name: 'notebook_name',
|
||||||
|
placeholder: '-',
|
||||||
|
sortable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '作业状态',
|
||||||
|
name: 'status_name',
|
||||||
|
placeholder: '-',
|
||||||
|
sortable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '作业分数',
|
||||||
|
name: 'score',
|
||||||
|
placeholder: '-',
|
||||||
|
sortable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button-group',
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '批阅',
|
||||||
|
level: 'primary',
|
||||||
|
size: 'xs',
|
||||||
|
actionType: 'dialog',
|
||||||
|
visibleOn:
|
||||||
|
'this.status === "notebook_submit" || this.status === "notebook_checked"',
|
||||||
|
dialog: {
|
||||||
|
title: '批阅作业',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'rest/project_scores?on_conflict=user_id,project_id,item',
|
||||||
|
data: {
|
||||||
|
score: '$score',
|
||||||
|
user_id: '$id',
|
||||||
|
project_id: '$project_id',
|
||||||
|
item: 'exp_notebook',
|
||||||
|
},
|
||||||
|
headers: {
|
||||||
|
Prefer: 'resolution=merge-duplicates',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
initApi: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/project_scores?user_id=eq.$id&project_id=eq.$project_id&item=eq.exp_notebook',
|
||||||
|
},
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'formula',
|
||||||
|
name: 'iframeSrc',
|
||||||
|
formula:
|
||||||
|
'location.origin + "/notebook/" + notebook_pid + "/" + notebook_post',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'iframe',
|
||||||
|
src: '${iframeSrc}',
|
||||||
|
height: '700px',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-number',
|
||||||
|
label: '分数',
|
||||||
|
name: 'score',
|
||||||
|
required: true,
|
||||||
|
mode: '',
|
||||||
|
value: 0,
|
||||||
|
min: '0',
|
||||||
|
max: '100',
|
||||||
|
step: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: 'dialog',
|
||||||
|
closeOnEsc: false,
|
||||||
|
closeOnOutside: false,
|
||||||
|
showCloseButton: true,
|
||||||
|
size: 'xl',
|
||||||
|
},
|
||||||
|
placeholder: '-',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:aab0a651813d',
|
||||||
|
label: '操作',
|
||||||
|
placeholder: '-',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
messages: {},
|
||||||
|
syncLocation: false,
|
||||||
|
pageField: 'page',
|
||||||
|
perPageField: 'perPage',
|
||||||
|
headerToolbar: [],
|
||||||
|
footerToolbar: [
|
||||||
|
{
|
||||||
|
type: 'pagination',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'switch-per-page',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'statistics',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
name: 'manage_loc',
|
||||||
|
perPageAvailable: [10, 20, 30, 40, 50],
|
||||||
|
filter: {
|
||||||
|
title: '',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
name: 'keywords',
|
||||||
|
label: '学生关键字',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'submit',
|
||||||
|
label: '搜索',
|
||||||
|
actionType: 'submit',
|
||||||
|
id: 'u:decd16bff04d',
|
||||||
|
level: 'primary',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
reload: 'manage_loc?keywords=$keywords',
|
||||||
|
canAccessSuperData: false,
|
||||||
|
wrapWithPanel: false,
|
||||||
|
autoFocus: false,
|
||||||
|
mode: 'inline',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
messages: {},
|
||||||
|
bodyClassName: '',
|
||||||
|
title: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
export { schema };
|
||||||
329
src/pages/schema/centre/computing/metric.schema.ts
Normal file
329
src/pages/schema/centre/computing/metric.schema.ts
Normal file
@@ -0,0 +1,329 @@
|
|||||||
|
const schema = {
|
||||||
|
type: 'page',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'service',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'flex',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
type: 'container',
|
||||||
|
id: 'u:cf018a54788b',
|
||||||
|
style: {
|
||||||
|
flexGrow: 1,
|
||||||
|
flexBasis: '0px',
|
||||||
|
flex: '1 1 auto',
|
||||||
|
display: 'flex',
|
||||||
|
position: 'static',
|
||||||
|
flexWrap: 'nowrap',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
flexDirection: 'column',
|
||||||
|
},
|
||||||
|
isFixedHeight: false,
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'progress',
|
||||||
|
id: 'u:9ae23711aada',
|
||||||
|
value: '$cpu',
|
||||||
|
placeholder: '-',
|
||||||
|
progressClassName: '',
|
||||||
|
strokeWidth: 10,
|
||||||
|
map: [
|
||||||
|
{ color: '#28a745', value: 30 },
|
||||||
|
{ color: '#fad733', value: 70 },
|
||||||
|
{ color: '#dc3545', value: 100 },
|
||||||
|
],
|
||||||
|
gapDegree: 75,
|
||||||
|
gapPosition: 'bottom',
|
||||||
|
mode: 'dashboard',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'tpl',
|
||||||
|
tpl: 'CPU',
|
||||||
|
inline: false,
|
||||||
|
wrapperComponent: '',
|
||||||
|
id: 'u:44a9ee228557',
|
||||||
|
themeCss: {
|
||||||
|
baseControlClassName: {
|
||||||
|
'font:default': { 'text-align': 'center' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'container',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'progress',
|
||||||
|
id: 'u:2fc35c429a6c',
|
||||||
|
value: '$memory',
|
||||||
|
placeholder: '-',
|
||||||
|
progressClassName: '',
|
||||||
|
strokeWidth: 10,
|
||||||
|
map: [
|
||||||
|
{ color: '#28a745', value: 30 },
|
||||||
|
{ color: '#fad733', value: 70 },
|
||||||
|
{ color: '#dc3545', value: 100 },
|
||||||
|
],
|
||||||
|
gapDegree: 75,
|
||||||
|
gapPosition: 'bottom',
|
||||||
|
mode: 'dashboard',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'tpl',
|
||||||
|
tpl: '内存',
|
||||||
|
inline: false,
|
||||||
|
wrapperComponent: '',
|
||||||
|
id: 'u:fd25e194e7b0',
|
||||||
|
themeCss: {
|
||||||
|
baseControlClassName: {
|
||||||
|
'font:default': { 'text-align': 'center' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 'none',
|
||||||
|
style: {
|
||||||
|
position: 'static',
|
||||||
|
display: 'flex',
|
||||||
|
flex: '1 1 auto',
|
||||||
|
flexGrow: 1,
|
||||||
|
flexWrap: 'nowrap',
|
||||||
|
alignItems: 'center',
|
||||||
|
flexBasis: '0px',
|
||||||
|
justifyContent: 'center',
|
||||||
|
flexDirection: 'column',
|
||||||
|
},
|
||||||
|
wrapperBody: false,
|
||||||
|
isFixedHeight: false,
|
||||||
|
isFixedWidth: false,
|
||||||
|
id: 'u:10e16e97e026',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'container',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'progress',
|
||||||
|
id: 'u:c1f3e318e1d2',
|
||||||
|
value: '$disk',
|
||||||
|
placeholder: '-',
|
||||||
|
progressClassName: '',
|
||||||
|
strokeWidth: 10,
|
||||||
|
map: [
|
||||||
|
{ color: '#28a745', value: 30 },
|
||||||
|
{ color: '#fad733', value: 70 },
|
||||||
|
{ color: '#dc3545', value: 100 },
|
||||||
|
],
|
||||||
|
gapDegree: 75,
|
||||||
|
gapPosition: 'bottom',
|
||||||
|
mode: 'dashboard',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'tpl',
|
||||||
|
tpl: '磁盘',
|
||||||
|
inline: false,
|
||||||
|
wrapperComponent: '',
|
||||||
|
id: 'u:11b1d296b866',
|
||||||
|
themeCss: {
|
||||||
|
baseControlClassName: {
|
||||||
|
'font:default': { 'text-align': 'center' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 'none',
|
||||||
|
style: {
|
||||||
|
position: 'static',
|
||||||
|
display: 'flex',
|
||||||
|
flex: '1 1 auto',
|
||||||
|
flexGrow: 1,
|
||||||
|
flexWrap: 'nowrap',
|
||||||
|
alignItems: 'center',
|
||||||
|
flexBasis: '0px',
|
||||||
|
justifyContent: 'center',
|
||||||
|
overflowY: 'visible',
|
||||||
|
flexDirection: 'column',
|
||||||
|
},
|
||||||
|
wrapperBody: false,
|
||||||
|
isFixedHeight: false,
|
||||||
|
isFixedWidth: false,
|
||||||
|
id: 'u:d63bc21af893',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'container',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'tpl',
|
||||||
|
tpl: '当前驱动版本:${gpu.driver}',
|
||||||
|
inline: true,
|
||||||
|
wrapperComponent: '',
|
||||||
|
id: 'u:b66aa4e0241d',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'cards',
|
||||||
|
columnsCount: 1,
|
||||||
|
card: {
|
||||||
|
type: 'container',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'tpl',
|
||||||
|
tpl: '${name}',
|
||||||
|
inline: true,
|
||||||
|
wrapperComponent: '',
|
||||||
|
id: 'u:702c8fcd1378',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'progress',
|
||||||
|
value: '$percent',
|
||||||
|
placeholder: '-',
|
||||||
|
progressClassName: '',
|
||||||
|
strokeWidth: 10,
|
||||||
|
map: [
|
||||||
|
{ color: '#28a745', value: 30 },
|
||||||
|
{ color: '#fad733', value: 70 },
|
||||||
|
{ color: '#dc3545', value: 100 },
|
||||||
|
],
|
||||||
|
gapDegree: 75,
|
||||||
|
gapPosition: 'bottom',
|
||||||
|
mode: 'dashboard',
|
||||||
|
id: 'u:376de1b837de',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
wrapperBody: false,
|
||||||
|
style: {
|
||||||
|
position: 'relative',
|
||||||
|
display: 'flex',
|
||||||
|
width: '100%',
|
||||||
|
flexWrap: 'nowrap',
|
||||||
|
inset: 'auto',
|
||||||
|
justifyContent: 'space-evenly',
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
themeCss: {
|
||||||
|
baseControlClassName: {
|
||||||
|
'radius:default': {
|
||||||
|
'top-left-border-radius': '6px',
|
||||||
|
'top-right-border-radius': '6px',
|
||||||
|
'bottom-left-border-radius': '6px',
|
||||||
|
'bottom-right-border-radius': '6px',
|
||||||
|
},
|
||||||
|
'boxShadow:default':
|
||||||
|
' 0px 0px 10px 0px var(--colors-neutral-line-8)',
|
||||||
|
'border:default': {
|
||||||
|
'top-border-width': 'var(--borders-width-1)',
|
||||||
|
'left-border-width': 'var(--borders-width-1)',
|
||||||
|
'right-border-width': 'var(--borders-width-1)',
|
||||||
|
'bottom-border-width': 'var(--borders-width-1)',
|
||||||
|
'top-border-style': 'var(--borders-style-1)',
|
||||||
|
'left-border-style': 'var(--borders-style-1)',
|
||||||
|
'right-border-style': 'var(--borders-style-1)',
|
||||||
|
'bottom-border-style': 'var(--borders-style-1)',
|
||||||
|
'top-border-color': '#3be157',
|
||||||
|
'left-border-color': '#3be157',
|
||||||
|
'right-border-color': '#3be157',
|
||||||
|
'bottom-border-color': '#3be157',
|
||||||
|
},
|
||||||
|
'padding-and-margin:default': {
|
||||||
|
paddingTop: '10px',
|
||||||
|
paddingRight: '10px',
|
||||||
|
paddingBottom: '10px',
|
||||||
|
paddingLeft: '10px',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
id: 'u:537200fb743f',
|
||||||
|
isFixedHeight: false,
|
||||||
|
isFixedWidth: false,
|
||||||
|
},
|
||||||
|
placeholder: '',
|
||||||
|
style: { gutterY: 10 },
|
||||||
|
id: 'u:f886cae9f2af',
|
||||||
|
name: 'gpu.list',
|
||||||
|
className: 'mt-5',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 'none',
|
||||||
|
style: {
|
||||||
|
position: 'static',
|
||||||
|
display: 'block',
|
||||||
|
flex: '1 1 auto',
|
||||||
|
flexGrow: 2,
|
||||||
|
flexBasis: 0,
|
||||||
|
},
|
||||||
|
wrapperBody: false,
|
||||||
|
isFixedHeight: false,
|
||||||
|
isFixedWidth: false,
|
||||||
|
id: 'u:6915a8d9638a',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
style: { position: 'relative', rowGap: '10px', columnGap: '10px' },
|
||||||
|
id: 'u:e4d85d1072cf',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:6399a46b9a99',
|
||||||
|
dsType: 'api',
|
||||||
|
ws: { url: 'ws://peiyun.host.platosoft.org:7080/api/nb/ws/metrics' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'crud',
|
||||||
|
syncLocation: false,
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: '/hub/users',
|
||||||
|
data: {},
|
||||||
|
messages: {},
|
||||||
|
requestAdaptor: '',
|
||||||
|
adaptor: '',
|
||||||
|
dataType: 'json',
|
||||||
|
},
|
||||||
|
bulkActions: [],
|
||||||
|
itemActions: [],
|
||||||
|
id: 'u:bd445262be74',
|
||||||
|
perPageAvailable: [5, 10, 20, 50, 100],
|
||||||
|
messages: {},
|
||||||
|
listItem: {
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
name: 'name',
|
||||||
|
label: '用户',
|
||||||
|
type: 'text',
|
||||||
|
id: 'u:83674005c420',
|
||||||
|
inline: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'datetime',
|
||||||
|
format: 'YYYY-MM-DD HH:mm:ss',
|
||||||
|
value: 1729753248,
|
||||||
|
name: 'last_activity',
|
||||||
|
id: 'u:92420a25ff12',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '停止',
|
||||||
|
onEvent: { click: { actions: [] } },
|
||||||
|
id: 'u:2384629a386e',
|
||||||
|
level: 'danger',
|
||||||
|
icon: 'fa fa-power-off',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:aaf60b5849b5',
|
||||||
|
},
|
||||||
|
mode: 'list',
|
||||||
|
loadDataOnce: true,
|
||||||
|
matchFunc: '',
|
||||||
|
className: 'mt-10',
|
||||||
|
title: '用户列表',
|
||||||
|
showHeader: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:4b1560f3b2db',
|
||||||
|
asideResizor: false,
|
||||||
|
pullRefresh: { disabled: true },
|
||||||
|
};
|
||||||
|
|
||||||
|
export { schema };
|
||||||
148
src/pages/schema/centre/computing/model.schema.ts
Normal file
148
src/pages/schema/centre/computing/model.schema.ts
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
const schema = {
|
||||||
|
type: 'page',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'dataset-renderer',
|
||||||
|
name: 'storage',
|
||||||
|
bucket: 'model',
|
||||||
|
addFolder: {
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'dialog',
|
||||||
|
reload: 'storage',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '新建文件夹',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'storage/v1/object/model/$path/$name/.empty',
|
||||||
|
requestAdaptor:
|
||||||
|
"api.url = api.url.replace('//', '/');return api",
|
||||||
|
},
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
label: '文件夹名称',
|
||||||
|
name: 'name',
|
||||||
|
mode: 'normal',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
moveFile: {
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'dialog',
|
||||||
|
reload: 'storage',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '重命名',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'storage/v1/object/move',
|
||||||
|
data: {
|
||||||
|
bucketId: 'model',
|
||||||
|
sourceKey: '$sourceKey',
|
||||||
|
dest: '$dest',
|
||||||
|
path: '$path',
|
||||||
|
},
|
||||||
|
requestAdaptor:
|
||||||
|
"console.log(api)\r\nreturn {\r\n ...api,\r\n data: {\r\n bucketId: api.data.bucketId,\r\n sourceKey: api.data.sourceKey,\r\n destinationKey: api.data.path === '' ? api.data.dest : api.data.path + '/' + api.data.dest\r\n }\r\n}",
|
||||||
|
},
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
name: 'dest',
|
||||||
|
type: 'input-text',
|
||||||
|
label: '名称',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
delFile: {
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'ajax',
|
||||||
|
reload: 'storage',
|
||||||
|
label: false,
|
||||||
|
api: {
|
||||||
|
method: 'delete',
|
||||||
|
url: '/storage/v1/object/model',
|
||||||
|
data: {
|
||||||
|
prefixes: '$prefixes',
|
||||||
|
},
|
||||||
|
headers: {
|
||||||
|
post2rest: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
confirmText: '确认删除吗?',
|
||||||
|
},
|
||||||
|
delFiles: {
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'dialog',
|
||||||
|
reload: 'storage',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '批量删除文件',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
api: {
|
||||||
|
method: 'delete',
|
||||||
|
url: 'storage/v1/object/model',
|
||||||
|
data: { prefixes: '$prefixes', path: '$path' },
|
||||||
|
headers: { post2rest: false },
|
||||||
|
requestAdaptor:
|
||||||
|
"return {\r\n ...api,\r\n data: {\r\n prefixes: api.data.prefixes.map(item => api.data.path === '' ? item : api.data.path + '/' + item)\r\n }\r\n}",
|
||||||
|
},
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
name: 'prefixes',
|
||||||
|
type: 'checkboxes',
|
||||||
|
label: false,
|
||||||
|
inline: false,
|
||||||
|
checkAll: true,
|
||||||
|
joinValues: false,
|
||||||
|
extractValue: true,
|
||||||
|
required: true,
|
||||||
|
source: {
|
||||||
|
method: 'post',
|
||||||
|
url: '/storage/v1/object/list/model',
|
||||||
|
data: {
|
||||||
|
prefix: '$path',
|
||||||
|
sortBy: {
|
||||||
|
column: 'name',
|
||||||
|
order: 'asc',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: payload.data.filter(item => item.id && item.name.charAt(0) !== ".").map(item => {\r\n return {\r\n label: item.name,\r\n value: item.name\r\n }\r\n })\r\n}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
,
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export { schema };
|
||||||
657
src/pages/schema/centre/computing/subject.schema.ts
Normal file
657
src/pages/schema/centre/computing/subject.schema.ts
Normal file
@@ -0,0 +1,657 @@
|
|||||||
|
const schema = {
|
||||||
|
type: 'page',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'crud',
|
||||||
|
messages: {},
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/subjects?order=name',
|
||||||
|
data: {
|
||||||
|
name: 'like.%${name}%',
|
||||||
|
},
|
||||||
|
requestAdaptor:
|
||||||
|
"if (api.query.name === 'like.%%') {\r\n api.url = api.url.replace('&name=like.%25%25', '')\r\n}\r\n\r\nreturn api;",
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: {\r\n ...payload.data,\r\n items: payload.data.items.map(item => {\r\n return {\r\n ...item,\r\n sname: item.name,\r\n temp: item.content.map(item => {\r\n return {\r\n ...item,\r\n mooc: item.session.filter(item => item.split("-")[1] === "mooc"),\r\n notebook: item.session.filter(item => item.split("-")[1] === "notebook")\r\n }\r\n })\r\n }\r\n })\r\n }\r\n}',
|
||||||
|
},
|
||||||
|
headerToolbar: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
align: 'right',
|
||||||
|
label: '添加',
|
||||||
|
icon: 'fa fa-plus',
|
||||||
|
level: 'default',
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '添加专题',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'control',
|
||||||
|
label: '',
|
||||||
|
mode: 'normal',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'grid',
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
label: '名称',
|
||||||
|
name: 'sname',
|
||||||
|
type: 'input-text',
|
||||||
|
mode: 'normal',
|
||||||
|
required: true,
|
||||||
|
id: 'u:f72c2d77e3a4',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:8c6f142936c2',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:c60d1c6c17ae',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:1aab6d05c2f2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '内容管理',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '内容管理',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
reload: 'subject?content=$content',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
label: '内容',
|
||||||
|
type: 'combo',
|
||||||
|
name: 'temp',
|
||||||
|
multiple: true,
|
||||||
|
multiLine: true,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
label: '描述',
|
||||||
|
type: 'textarea',
|
||||||
|
name: 'intro',
|
||||||
|
mode: 'normal',
|
||||||
|
id: 'u:86fa1674235c',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'picker',
|
||||||
|
label: '课程',
|
||||||
|
name: 'mooc',
|
||||||
|
valueField: 'value',
|
||||||
|
labelField: 'name',
|
||||||
|
modalClassName: 'app-popover',
|
||||||
|
id: 'u:c8e1e52ea0b1',
|
||||||
|
modalMode: 'dialog',
|
||||||
|
strictMode: false,
|
||||||
|
multiple: true,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/mooc?name=${name}&order=name',
|
||||||
|
data: {
|
||||||
|
page: '${page}',
|
||||||
|
perPage: '${perPage}',
|
||||||
|
name: 'like.%${name}%',
|
||||||
|
},
|
||||||
|
requestAdaptor:
|
||||||
|
"if (api.query.name === 'like.%%') {\r\n api.url = api.url.replace('&name=like.%25%25', '')\r\n}\r\n\r\nreturn api;",
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: {\r\n ...payload.data,\r\n items: payload.data.items.map(item => {\r\n return {\r\n ...item,\r\n value: item.id + "-" + item.type + "-" + item.name\r\n }\r\n })\r\n }\r\n}',
|
||||||
|
},
|
||||||
|
joinValues: false,
|
||||||
|
extractValue: true,
|
||||||
|
embed: true,
|
||||||
|
pickerSchema: {
|
||||||
|
mode: 'table',
|
||||||
|
id: 'u:ae755822f652',
|
||||||
|
perPageAvailable: [10],
|
||||||
|
messages: {},
|
||||||
|
syncLocation: false,
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '编号',
|
||||||
|
name: 'code',
|
||||||
|
id: 'u:636f3f0a2ed3',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '名称',
|
||||||
|
name: 'name',
|
||||||
|
searchable: true,
|
||||||
|
id: 'u:636f3f0a2ed3',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'picker',
|
||||||
|
label: '文档',
|
||||||
|
name: 'notebook',
|
||||||
|
valueField: 'value',
|
||||||
|
labelField: 'name',
|
||||||
|
modalClassName: 'app-popover',
|
||||||
|
id: 'u:0a92044686ee',
|
||||||
|
modalMode: 'dialog',
|
||||||
|
strictMode: false,
|
||||||
|
multiple: true,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/notebooks?name=${name}&author=${author}&order=name',
|
||||||
|
data: {
|
||||||
|
page: '${page}',
|
||||||
|
perPage: '${perPage}',
|
||||||
|
name: 'like.%${name}%',
|
||||||
|
author: 'like.%${author}%',
|
||||||
|
},
|
||||||
|
requestAdaptor:
|
||||||
|
"if (api.query.name === 'like.%%') {\r\n api.url = api.url.replace('&name=like.%25%25', '')\r\n}\r\n\r\nif (api.query.author === 'like.%%') {\r\n api.url = api.url.replace('&author=like.%25%25', '')\r\n}\r\n\r\nreturn api;",
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: {\r\n ...payload.data,\r\n items: payload.data.items.map(item => {\r\n return {\r\n ...item,\r\n value: item.id + "-" + item.type + "-" + item.name\r\n }\r\n })\r\n }\r\n}',
|
||||||
|
},
|
||||||
|
joinValues: false,
|
||||||
|
extractValue: true,
|
||||||
|
embed: true,
|
||||||
|
pickerSchema: {
|
||||||
|
mode: 'table',
|
||||||
|
id: 'u:ae755822f652',
|
||||||
|
perPageAvailable: [10],
|
||||||
|
messages: {},
|
||||||
|
syncLocation: false,
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '名称',
|
||||||
|
name: 'name',
|
||||||
|
searchable: true,
|
||||||
|
id: 'u:636f3f0a2ed3',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '作者',
|
||||||
|
name: 'author',
|
||||||
|
searchable: true,
|
||||||
|
id: 'u:636f3f0a2ed3',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'formula',
|
||||||
|
name: 'content',
|
||||||
|
formula:
|
||||||
|
'data.temp.map(item => { return { intro: item.intro, session: item.mooc.concat(item.notebook).filter(item => item) } })',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:d2e6bd28f354',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
showCloseButton: true,
|
||||||
|
showErrorMsg: true,
|
||||||
|
showLoading: true,
|
||||||
|
className: 'app-popover',
|
||||||
|
id: 'u:b6ff11656496',
|
||||||
|
closeOnEsc: true,
|
||||||
|
size: 'lg',
|
||||||
|
withDefaultData: false,
|
||||||
|
dataMapSwitch: true,
|
||||||
|
data: {
|
||||||
|
'&': '$$',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
id: 'u:739469c288af',
|
||||||
|
level: 'primary',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-array',
|
||||||
|
label: '内容',
|
||||||
|
name: 'content',
|
||||||
|
id: 'u:561926ea3025',
|
||||||
|
items: {
|
||||||
|
type: 'combo',
|
||||||
|
label: '',
|
||||||
|
controls: [
|
||||||
|
{
|
||||||
|
type: 'tpl',
|
||||||
|
label: '介绍',
|
||||||
|
tpl: '$intro',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-array',
|
||||||
|
label: '内容',
|
||||||
|
name: 'session',
|
||||||
|
id: 'u:561926ea3025',
|
||||||
|
items: {
|
||||||
|
type: 'tpl',
|
||||||
|
id: 'u:f95cfcfcc0fb',
|
||||||
|
},
|
||||||
|
addable: false,
|
||||||
|
removable: true,
|
||||||
|
draggable: true,
|
||||||
|
isSlot: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:f95cfcfcc0fb',
|
||||||
|
multiLine: false,
|
||||||
|
multiple: false,
|
||||||
|
messages: {},
|
||||||
|
},
|
||||||
|
addable: false,
|
||||||
|
removable: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'rest/subjects',
|
||||||
|
data: {
|
||||||
|
name: '$sname',
|
||||||
|
content: '$content',
|
||||||
|
},
|
||||||
|
dataType: 'json',
|
||||||
|
},
|
||||||
|
name: 'subject',
|
||||||
|
id: 'u:6ddf84e7e06c',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
size: 'lg',
|
||||||
|
id: 'u:2f4c08ecc48e',
|
||||||
|
},
|
||||||
|
name: 'semesterSelect',
|
||||||
|
options: [],
|
||||||
|
checkAll: false,
|
||||||
|
submitOnChange: true,
|
||||||
|
autoComplete: '',
|
||||||
|
mode: 'inline',
|
||||||
|
className: '',
|
||||||
|
id: 'u:8eee4a809327',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
syncLocation: false,
|
||||||
|
name: 'plan',
|
||||||
|
footerToolbar: [],
|
||||||
|
affixHeader: true,
|
||||||
|
placeholder: '暂无数据',
|
||||||
|
mode: 'cards',
|
||||||
|
card: {
|
||||||
|
type: 'card',
|
||||||
|
header: {
|
||||||
|
title: '$name',
|
||||||
|
},
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
label: '',
|
||||||
|
type: 'button-group',
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '',
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
title: '修改专题',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
data: { '&': '$$', name: '__undefined' },
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'control',
|
||||||
|
label: '',
|
||||||
|
mode: 'normal',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'grid',
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
label: '名称',
|
||||||
|
name: 'sname',
|
||||||
|
type: 'input-text',
|
||||||
|
mode: 'normal',
|
||||||
|
required: true,
|
||||||
|
id: 'u:f72c2d77e3a4',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:8c6f142936c2',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:c60d1c6c17ae',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:1aab6d05c2f2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '内容管理',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '内容管理',
|
||||||
|
data: { '&': '$$', name: '__undefined' },
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
reload: 'subject?content=$content',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
label: '内容',
|
||||||
|
type: 'combo',
|
||||||
|
name: 'temp',
|
||||||
|
multiple: true,
|
||||||
|
multiLine: true,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
label: '描述',
|
||||||
|
type: 'textarea',
|
||||||
|
name: 'intro',
|
||||||
|
mode: 'normal',
|
||||||
|
id: 'u:86fa1674235c',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'picker',
|
||||||
|
label: '课程',
|
||||||
|
name: 'mooc',
|
||||||
|
valueField: 'value',
|
||||||
|
labelField: 'name',
|
||||||
|
modalClassName: 'app-popover',
|
||||||
|
id: 'u:c8e1e52ea0b1',
|
||||||
|
modalMode: 'dialog',
|
||||||
|
strictMode: false,
|
||||||
|
multiple: true,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/mooc?name=${name}&order=name',
|
||||||
|
data: {
|
||||||
|
page: '${page}',
|
||||||
|
perPage: '${perPage}',
|
||||||
|
name: 'like.%${name}%',
|
||||||
|
},
|
||||||
|
requestAdaptor:
|
||||||
|
"if (api.query.name === 'like.%%') {\r\n api.url = api.url.replace('&name=like.%25%25', '')\r\n}\r\n\r\nreturn api;",
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: {\r\n ...payload.data,\r\n items: payload.data.items.map(item => {\r\n return {\r\n ...item,\r\n value: item.id + "-" + item.type + "-" + item.name\r\n }\r\n })\r\n }\r\n}',
|
||||||
|
},
|
||||||
|
joinValues: false,
|
||||||
|
extractValue: true,
|
||||||
|
embed: true,
|
||||||
|
pickerSchema: {
|
||||||
|
mode: 'table',
|
||||||
|
id: 'u:ae755822f652',
|
||||||
|
perPageAvailable: [10],
|
||||||
|
messages: {},
|
||||||
|
syncLocation: false,
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '编号',
|
||||||
|
name: 'code',
|
||||||
|
id: 'u:636f3f0a2ed3',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '名称',
|
||||||
|
name: 'name',
|
||||||
|
searchable: true,
|
||||||
|
id: 'u:636f3f0a2ed3',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'picker',
|
||||||
|
label: '文档',
|
||||||
|
name: 'notebook',
|
||||||
|
valueField: 'value',
|
||||||
|
labelField: 'name',
|
||||||
|
modalClassName: 'app-popover',
|
||||||
|
id: 'u:0a92044686ee',
|
||||||
|
modalMode: 'dialog',
|
||||||
|
strictMode: false,
|
||||||
|
multiple: true,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/notebooks?name=${name}&author=${author}&order=name',
|
||||||
|
data: {
|
||||||
|
page: '${page}',
|
||||||
|
perPage: '${perPage}',
|
||||||
|
name: 'like.%${name}%',
|
||||||
|
author: 'like.%${author}%',
|
||||||
|
},
|
||||||
|
requestAdaptor:
|
||||||
|
"if (api.query.name === 'like.%%') {\r\n api.url = api.url.replace('&name=like.%25%25', '')\r\n}\r\n\r\nif (api.query.author === 'like.%%') {\r\n api.url = api.url.replace('&author=like.%25%25', '')\r\n}\r\n\r\nreturn api;",
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: {\r\n ...payload.data,\r\n items: payload.data.items.map(item => {\r\n return {\r\n ...item,\r\n value: item.id + "-" + item.type + "-" + item.name\r\n }\r\n })\r\n }\r\n}',
|
||||||
|
},
|
||||||
|
joinValues: false,
|
||||||
|
extractValue: true,
|
||||||
|
embed: true,
|
||||||
|
pickerSchema: {
|
||||||
|
mode: 'table',
|
||||||
|
id: 'u:ae755822f652',
|
||||||
|
perPageAvailable: [10],
|
||||||
|
messages: {},
|
||||||
|
syncLocation: false,
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '名称',
|
||||||
|
name: 'name',
|
||||||
|
searchable: true,
|
||||||
|
id: 'u:636f3f0a2ed3',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '作者',
|
||||||
|
name: 'author',
|
||||||
|
searchable: true,
|
||||||
|
id: 'u:636f3f0a2ed3',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'formula',
|
||||||
|
name: 'content',
|
||||||
|
formula:
|
||||||
|
'data.temp.map(item => { return { intro: item.intro, session: item.mooc.concat(item.notebook).filter(item => item) } })',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:d2e6bd28f354',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
showCloseButton: true,
|
||||||
|
showErrorMsg: true,
|
||||||
|
showLoading: true,
|
||||||
|
className: 'app-popover',
|
||||||
|
id: 'u:b6ff11656496',
|
||||||
|
closeOnEsc: true,
|
||||||
|
size: 'lg',
|
||||||
|
withDefaultData: false,
|
||||||
|
dataMapSwitch: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
id: 'u:739469c288af',
|
||||||
|
level: 'primary',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-array',
|
||||||
|
label: '内容',
|
||||||
|
name: 'content',
|
||||||
|
id: 'u:561926ea3025',
|
||||||
|
items: {
|
||||||
|
type: 'combo',
|
||||||
|
label: '',
|
||||||
|
controls: [
|
||||||
|
{
|
||||||
|
type: 'tpl',
|
||||||
|
label: '介绍',
|
||||||
|
tpl: '$intro',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-array',
|
||||||
|
label: '内容',
|
||||||
|
name: 'session',
|
||||||
|
id: 'u:561926ea3025',
|
||||||
|
items: {
|
||||||
|
type: 'tpl',
|
||||||
|
id: 'u:f95cfcfcc0fb',
|
||||||
|
},
|
||||||
|
addable: false,
|
||||||
|
removable: true,
|
||||||
|
draggable: true,
|
||||||
|
isSlot: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:f95cfcfcc0fb',
|
||||||
|
multiLine: false,
|
||||||
|
multiple: false,
|
||||||
|
messages: {},
|
||||||
|
},
|
||||||
|
addable: false,
|
||||||
|
removable: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
api: {
|
||||||
|
method: 'patch',
|
||||||
|
url: 'rest/subjects/${id}',
|
||||||
|
data: {
|
||||||
|
name: '$sname',
|
||||||
|
content: '$content',
|
||||||
|
},
|
||||||
|
dataType: 'json',
|
||||||
|
},
|
||||||
|
name: 'subject',
|
||||||
|
id: 'u:6ddf84e7e06c',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: 'dialog',
|
||||||
|
size: 'md',
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
},
|
||||||
|
icon: 'fa fa-pencil text-info',
|
||||||
|
level: 'link',
|
||||||
|
size: 'md',
|
||||||
|
target: '',
|
||||||
|
block: false,
|
||||||
|
tooltip: '修改专题',
|
||||||
|
tooltipPlacement: 'top',
|
||||||
|
iconClassName: 'pull-left',
|
||||||
|
className: 'p-r-none p-l-none',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '',
|
||||||
|
actionType: 'ajax',
|
||||||
|
icon: 'fa fa-trash text-danger',
|
||||||
|
iconClassName: 'pull-left',
|
||||||
|
confirmText: '确认删除"${name}"?',
|
||||||
|
api: {
|
||||||
|
method: 'delete',
|
||||||
|
url: 'rest/subjects/${id}',
|
||||||
|
},
|
||||||
|
level: 'link',
|
||||||
|
size: 'md',
|
||||||
|
tooltip: '删除专题',
|
||||||
|
tooltipPlacement: 'top',
|
||||||
|
className: 'p-r-none p-l-none',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'divider',
|
||||||
|
label: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'tabs',
|
||||||
|
label: '',
|
||||||
|
tabs: [
|
||||||
|
{
|
||||||
|
title: '内容',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'list',
|
||||||
|
listItem: {
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'html',
|
||||||
|
html: '$intro',
|
||||||
|
wrapperComponent: '',
|
||||||
|
id: 'u:d6c7aa76d24f',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-array',
|
||||||
|
name: 'session',
|
||||||
|
items: {
|
||||||
|
type: 'html',
|
||||||
|
},
|
||||||
|
addable: false,
|
||||||
|
removable: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
actions: [],
|
||||||
|
id: 'u:1ddb9863eba8',
|
||||||
|
},
|
||||||
|
id: 'u:6a6d7608b012',
|
||||||
|
source: '$content',
|
||||||
|
placeholder: '没有数据',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
className: 'tab',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
actions: [],
|
||||||
|
actionsCount: 4,
|
||||||
|
},
|
||||||
|
columnsCount: 1,
|
||||||
|
loadDataOnce: true,
|
||||||
|
masonryLayout: false,
|
||||||
|
itemClassName: '',
|
||||||
|
checkAll: false,
|
||||||
|
id: 'u:f2d78d4b8af6',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
cssVars: {
|
||||||
|
'--Form-item-gap': 0,
|
||||||
|
},
|
||||||
|
headerToolbar: [],
|
||||||
|
id: 'u:9891040f8810',
|
||||||
|
};
|
||||||
|
|
||||||
|
export { schema };
|
||||||
1453
src/pages/schema/centre/data/index.schema.ts
Normal file
1453
src/pages/schema/centre/data/index.schema.ts
Normal file
File diff suppressed because it is too large
Load Diff
850
src/pages/schema/centre/data/task.schema.ts
Normal file
850
src/pages/schema/centre/data/task.schema.ts
Normal file
@@ -0,0 +1,850 @@
|
|||||||
|
const schema = {
|
||||||
|
type: 'page',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'tabs',
|
||||||
|
className: '',
|
||||||
|
tabs: [
|
||||||
|
{
|
||||||
|
title: '日程一览',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
className: '',
|
||||||
|
submitOnChange: true,
|
||||||
|
submitOnInit: true,
|
||||||
|
reload:
|
||||||
|
'manage_loc?course_id=$course_id&project_id=$project_id&teacher_id=$teacher_id&location_id=$location_id&date=$date&no_tch=$no_tch&public=$public&semesterSelect=$semesterSelect',
|
||||||
|
initApi: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/users?role=eq.teacher&id=eq.${user.id}&order=code',
|
||||||
|
requestAdaptor: '',
|
||||||
|
adaptor:
|
||||||
|
"if (payload.data.items.length !== 0) {\r\n return {\r\n teacher_id: 'eq.'.concat(payload.data.items[0].id)\r\n }\r\n} else {\r\n return {}\r\n}",
|
||||||
|
},
|
||||||
|
wrapWithPanel: false,
|
||||||
|
mode: 'inline',
|
||||||
|
name: 'filter',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'group',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
label: '历史',
|
||||||
|
name: 'semesterSelect',
|
||||||
|
mode: 'inline',
|
||||||
|
clearable: false,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/semesters?order=is_open.desc,since.desc',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: {\r\n ...payload.data,\r\n items: payload.data.items.map(item => {\r\n return {\r\n label: item.name,\r\n value: item.id\r\n }\r\n })\r\n }\r\n}',
|
||||||
|
},
|
||||||
|
checkAll: false,
|
||||||
|
size: 'md',
|
||||||
|
searchable: true,
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
options: [],
|
||||||
|
id: 'u:66e672b9a4eb',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
label: '课程',
|
||||||
|
name: 'course_id',
|
||||||
|
mode: 'inline',
|
||||||
|
clearable: true,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/courses?organization_id=eq.$centre_id&semester_id=eq.$semesterSelect&order=code',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: payload.data.items.map(item => {\r\n return {\r\n label: `${item.name}(${item.code})`,\r\n value: "eq.".concat(item.id)\r\n }\r\n })\r\n}',
|
||||||
|
},
|
||||||
|
checkAll: false,
|
||||||
|
size: 'md',
|
||||||
|
searchable: true,
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
id: 'u:834c027e3f4a',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
mode: 'inline',
|
||||||
|
label: '项目',
|
||||||
|
name: 'project_id',
|
||||||
|
clearable: true,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/projects?organization_id=eq.$centre_id&semester_id=eq.$semesterSelect&order=code',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: payload.data.items.map(item => {\r\n return {\r\n label: item.name,\r\n value: "eq.".concat(item.id)\r\n }\r\n })\r\n}',
|
||||||
|
},
|
||||||
|
checkAll: false,
|
||||||
|
size: 'md',
|
||||||
|
searchable: true,
|
||||||
|
className: 'm-l-sm',
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
id: 'u:ce7be11036a7',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:5014fc9e9daf',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'group',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'input-date-range',
|
||||||
|
label: '日期',
|
||||||
|
name: 'date',
|
||||||
|
mode: 'inline',
|
||||||
|
clearable: true,
|
||||||
|
value: '',
|
||||||
|
format: 'YYYY-MM-DD',
|
||||||
|
ranges:
|
||||||
|
'yesterday,today,7daysago,prevweek,thismonth,prevmonth,prevquarter',
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
id: 'u:105a2c1566be',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '地点',
|
||||||
|
type: 'select',
|
||||||
|
name: 'location_id',
|
||||||
|
mode: 'inline',
|
||||||
|
clearable: true,
|
||||||
|
checkAll: false,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/locations?organization_id=eq.$centre_id&order=code',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: payload.data.items.map(item => {\r\n return {\r\n label: item.name,\r\n value: "eq.".concat(item.id)\r\n }\r\n })\r\n}',
|
||||||
|
},
|
||||||
|
size: 'md',
|
||||||
|
searchable: true,
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
className: 'm-l-sm',
|
||||||
|
id: 'u:da7fb6289bbf',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
name: 'teacher_id',
|
||||||
|
mode: 'inline',
|
||||||
|
label: '教师',
|
||||||
|
clearable: true,
|
||||||
|
checkAll: false,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/users?role=eq.teacher&order=code',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: payload.data.items.map(item => {\r\n return {\r\n label: `${item.name}(${item.code})`,\r\n value: "eq.".concat(item.id)\r\n }\r\n })\r\n}',
|
||||||
|
},
|
||||||
|
size: 'md',
|
||||||
|
searchable: true,
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
className: 'm-l-sm',
|
||||||
|
id: 'u:9945a410d682',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:7ef4cbfbbc4c',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'group',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'switch',
|
||||||
|
name: 'no_tch',
|
||||||
|
option: '显示无教师场次',
|
||||||
|
mode: 'inline',
|
||||||
|
optionAtLeft: false,
|
||||||
|
trueValue: 1,
|
||||||
|
falseValue: 0,
|
||||||
|
value: 0,
|
||||||
|
inputClassName: '',
|
||||||
|
id: 'u:e9b5ab665ddf',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'switch',
|
||||||
|
name: 'public',
|
||||||
|
option: '显示公共场次',
|
||||||
|
mode: 'inline',
|
||||||
|
optionAtLeft: false,
|
||||||
|
trueValue: 1,
|
||||||
|
falseValue: 0,
|
||||||
|
value: 0,
|
||||||
|
inputClassName: 'm-l-sm',
|
||||||
|
id: 'u:984816e1593e',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:1de38c7bb180',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'divider',
|
||||||
|
lineStyle: 'solid',
|
||||||
|
id: 'u:f99b4d53b5dc',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:ca42a8e96c02',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'crud',
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/schedule_stats?organization_id=eq.$centre_id&semester_id=eq.$semesterSelect&is_publish=is.true&order=project_name,date,period_name,location_name,teacher_name',
|
||||||
|
data: {
|
||||||
|
page: '$page',
|
||||||
|
perPage: '$perPage',
|
||||||
|
'&': '$$',
|
||||||
|
},
|
||||||
|
adaptor:
|
||||||
|
"let supportDateTimeFormat = typeof(Intl.DateTimeFormat) === 'function';\r\npayload.data.items.forEach(item => {\r\n item.day = supportDateTimeFormat ? `${item.date}(${new Intl.DateTimeFormat('zh-CN', { weekday: 'short'}).format(new Date(item.date))})` : item.date;\r\n let att_count = item.att_y_count\r\n + item.att_y_late_count\r\n + item.att_y_unclean_count\r\n item.att_num = \"\".concat(\r\n att_count, \"/\", item.current_student_number\r\n )\r\n item.data_num = \"\".concat(\r\n item.data_count, '/', att_count\r\n )\r\n item.data_num_status =\r\n item.data_count === att_count\r\n ? 1\r\n : 0\r\n item.stu_title = item.project_name.concat(\r\n ' :: ', item.date, ' ', item.period_name,\r\n ' :: ', item.location_name,\r\n ' :: ', item.teacher_name ? item.teacher_name : '无教师认领'\r\n )\r\n})\r\n\r\nreturn {\r\n ...payload\r\n}",
|
||||||
|
requestAdaptor:
|
||||||
|
"if (api.query.semesterSelect) {\r\n api.url = api.url.replace(/&semesterSelect=\\d*/g, '')\r\n api.url = api.url.replace(/(?<=semester_id=eq\\.)\\d*(?=&)/g, api.query.semesterSelect)\r\n} else {\r\n api.url = api.url.replace(/&semesterSelect=/g, '')\r\n}\r\nif (api.body.course_id === '') {\r\n api.url = api.url.replace(/&course_id=/g, '')\r\n}\r\nif (api.body.project_id === '') {\r\n api.url = api.url.replace(/&project_id=/g, '')\r\n}\r\nif (api.body.date === '') {\r\n api.url = api.url.replace(/&date=/g, '')\r\n}\r\nif (api.body.location_id === '') {\r\n api.url = api.url.replace(/&location_id=/g, '')\r\n}\r\nif (api.body.teacher_id === '') {\r\n api.url = api.url.replace(/&teacher_id=/g, '')\r\n}\r\nif (api.body.no_tch === 0) {\r\n api.url = api.url.replace(/&no_tch=0/g, '')\r\n}\r\nif (api.body.public === 0) {\r\n api.url = api.url.replace(/&public=0/g, '')\r\n}\r\nconst pattern = /(?:date=)(\\d+-\\d+-\\d+)%2C(\\d+-\\d+-\\d+)/g\r\nconst result = pattern.exec(api.url)\r\nif (result && result[1] === result[2]) {\r\n api.url = api.url.replace(result[0], 'date=eq.'.concat(result[1]))\r\n} else if (result) {\r\n api.url = api.url.replace(result[0], 'date=gte.'.concat(result[1], '&date=lte.', result[2]))\r\n}\r\nconst is_no_tch = /no_tch=1/g.test(api.url)\r\nconst has_teacher = /teacher_id=.+?(?=&)/g.test(api.url)\r\nif (is_no_tch && has_teacher) {\r\n const teacher = /teacher_id=.+?(?=&)/g.exec(api.url)\r\n api.url = api.url.replace(teacher, 'or=('.concat(teacher, ',teacher_id.is.null)')).replace('teacher_id=', 'teacher_id.')\r\n api.url = api.url.replace(/no_tch=1/g, '')\r\n} else if (is_no_tch && !has_teacher) {\r\n api.url = api.url.replace(/no_tch=1/g, 'teacher_id=is.null')\r\n}\r\nconst is_public = /public=1/g.test(api.url)\r\nconst has_course = /course_id=.+?(?=&)/g.test(api.url)\r\nif (is_public && has_course) {\r\n const course = /course_id=.+?(?=&)/g.exec(api.url)\r\n api.url = api.url.replace(course, 'or=('.concat(course, ',course_id.is.null)')).replace('course_id=', 'course_id.')\r\n api.url = api.url.replace(/public=1/g, '')\r\n} else if (is_public && !has_course) {\r\n api.url = api.url.replace(/public=1/g, 'course_id=is.null')\r\n}\r\nreturn {\r\n ...api\r\n}",
|
||||||
|
},
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
type: 'tpl',
|
||||||
|
label: '项目',
|
||||||
|
tpl: '<% if(!this.course_id) { %>\n <span class="label label-info">公共</span><span> <%= this.project_name %> <span>\n<% } else {%>\n <span> <%= this.project_name %> <span>\n<% } %>',
|
||||||
|
inline: false,
|
||||||
|
placeholder: '-',
|
||||||
|
id: 'u:a41eff5b6b05',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'day',
|
||||||
|
label: '日期',
|
||||||
|
type: 'text',
|
||||||
|
placeholder: '-',
|
||||||
|
id: 'u:d4c925b1426d',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '节次',
|
||||||
|
name: 'period_name',
|
||||||
|
placeholder: '-',
|
||||||
|
id: 'u:97591d821213',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '地点',
|
||||||
|
name: 'location_name',
|
||||||
|
placeholder: '-',
|
||||||
|
id: 'u:d15f6350ec5c',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '教师',
|
||||||
|
name: 'teacher_name',
|
||||||
|
placeholder: '-',
|
||||||
|
id: 'u:bb4bb20fe052',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '考勤数',
|
||||||
|
placeholder: '-',
|
||||||
|
name: 'att_num',
|
||||||
|
id: 'u:d25f22581135',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button-group',
|
||||||
|
label: '操作',
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '查看学生',
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '学生信息',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'crud',
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/user2projects?select=*,att_status_text:user2project_att_status_dict_fk(dictvalue),schedule_status:user2project_schedule_status_dict_fk(dictvalue),student:users!user2project_student_id_fkey(*),projects(*)&schedule_id=eq.${id}&schedule_status=neq.canceled&order=id.asc',
|
||||||
|
data: {},
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: {\r\n ...payload.data,\r\n items: payload.data.items.map((item,index) => {\r\n return {\r\n ...item,\r\n row_number: index+1\r\n }\r\n })\r\n }\r\n}',
|
||||||
|
},
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
label: '序号',
|
||||||
|
type: 'plain',
|
||||||
|
inline: false,
|
||||||
|
name: 'row_number',
|
||||||
|
tpl: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'schedule_status.dictvalue',
|
||||||
|
label: '选课状态',
|
||||||
|
type: 'plain',
|
||||||
|
placeholder: '-',
|
||||||
|
inline: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'student.name',
|
||||||
|
label: '学生',
|
||||||
|
type: 'text',
|
||||||
|
placeholder: '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '学号',
|
||||||
|
name: 'student.code',
|
||||||
|
placeholder: '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '考勤状态',
|
||||||
|
name: 'att_status_text.dictvalue',
|
||||||
|
placeholder: '-',
|
||||||
|
groupName: '',
|
||||||
|
remark: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'operation',
|
||||||
|
label: '操作',
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '查看',
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '$student.name($student.code)',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'crud',
|
||||||
|
syncLocation: false,
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/tasks?select=*,dict_status:dicts!task_status_fkey(*),dict_type:dicts!task_type_fkey(*)&schedule_id=eq.$schedule_id&user_id=eq.$student.id',
|
||||||
|
messages: {},
|
||||||
|
requestAdaptor: '',
|
||||||
|
adaptor: '',
|
||||||
|
},
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'content',
|
||||||
|
label: '任务',
|
||||||
|
type: 'text',
|
||||||
|
id: 'u:b7848b797bf9',
|
||||||
|
placeholder: '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'dict_type.dictvalue',
|
||||||
|
label: '类型',
|
||||||
|
type: 'text',
|
||||||
|
id: 'u:f7ed595f5c57',
|
||||||
|
placeholder: '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
wrapperComponent: '',
|
||||||
|
id: 'u:80864ebd90a9',
|
||||||
|
label: '状态',
|
||||||
|
placeholder: '-',
|
||||||
|
name: 'dict_status.dictvalue',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
bulkActions: [],
|
||||||
|
itemActions: [],
|
||||||
|
id: 'u:3458736acc74',
|
||||||
|
perPageAvailable: [10],
|
||||||
|
messages: {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 'lg',
|
||||||
|
actions: [],
|
||||||
|
closeOnEsc: true,
|
||||||
|
closeOnOutside: false,
|
||||||
|
showCloseButton: true,
|
||||||
|
id: 'u:bc2fcc411e2a',
|
||||||
|
},
|
||||||
|
size: 'xs',
|
||||||
|
level: 'primary',
|
||||||
|
closeOnEsc: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
messages: {},
|
||||||
|
headerToolbar: [
|
||||||
|
{
|
||||||
|
type: 'tpl',
|
||||||
|
tpl: '${stu_title}',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
syncLocation: false,
|
||||||
|
affixHeader: false,
|
||||||
|
bodyClassName: '',
|
||||||
|
className: '',
|
||||||
|
perPageAvailable: [10],
|
||||||
|
name: 'schedule_data',
|
||||||
|
silentPolling: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 'lg',
|
||||||
|
actions: [],
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
closeOnOutside: false,
|
||||||
|
},
|
||||||
|
level: 'primary',
|
||||||
|
size: 'xs',
|
||||||
|
id: 'u:a05b0e0b829a',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
placeholder: '-',
|
||||||
|
id: 'u:8bd7633bd4c7',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
messages: {},
|
||||||
|
syncLocation: false,
|
||||||
|
pageField: 'page',
|
||||||
|
perPageField: 'perPage',
|
||||||
|
headerToolbar: [],
|
||||||
|
footerToolbar: [
|
||||||
|
{
|
||||||
|
type: 'pagination',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'switch-per-page',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'statistics',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
name: 'manage_loc',
|
||||||
|
perPageAvailable: [10, 20, 30, 40, 50],
|
||||||
|
id: 'u:6488ee7bd91a',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
className: 'p-t-none',
|
||||||
|
id: 'u:66531bc383d6',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '学生一览',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'grid',
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
md: 3,
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
reload:
|
||||||
|
'stu?parent=${tree}&tree=${tree}&org_name=${name}&type=${type}&filter=${filter}',
|
||||||
|
data: {
|
||||||
|
parentId: 1,
|
||||||
|
},
|
||||||
|
wrapWithPanel: false,
|
||||||
|
title: '表单',
|
||||||
|
submitOnChange: true,
|
||||||
|
target: '',
|
||||||
|
resetAfterSubmit: false,
|
||||||
|
initApi: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/orgs?type=eq.school',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: {\r\n tree: payload.data.id\r\n }\r\n}',
|
||||||
|
headers: {
|
||||||
|
Accept: 'application/vnd.pgrst.object+json',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'service',
|
||||||
|
name: 'service',
|
||||||
|
messages: {},
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/orgs/${tree}',
|
||||||
|
sendOn: 'this.tree',
|
||||||
|
},
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
label: '部门类型',
|
||||||
|
name: 'type',
|
||||||
|
visibleOn: 'false',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
label: '部门名称',
|
||||||
|
name: 'name',
|
||||||
|
visibleOn: 'false',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
label: '部门Path',
|
||||||
|
name: 'path',
|
||||||
|
visibleOn: 'false',
|
||||||
|
value: 'root',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
label: '过滤条件',
|
||||||
|
name: 'filter',
|
||||||
|
visibleOn: 'false',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'formula',
|
||||||
|
name: 'filter',
|
||||||
|
formula:
|
||||||
|
"'org_path.cd.' + data.path + '.' + data.tree + ',org_id.eq.' + data.tree",
|
||||||
|
condition: 'data.tree',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'formula',
|
||||||
|
name: 'filter',
|
||||||
|
formula: "'org_path.cd.root'",
|
||||||
|
condition: '!data.tree',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-tree',
|
||||||
|
label: '',
|
||||||
|
name: 'tree',
|
||||||
|
inputClassName: 'partment-height',
|
||||||
|
creatable: false,
|
||||||
|
removable: false,
|
||||||
|
editable: false,
|
||||||
|
deleteApi: 'rest/orgs/$id',
|
||||||
|
rootCreatable: false,
|
||||||
|
unfoldedLevel: 1,
|
||||||
|
initiallyOpen: false,
|
||||||
|
virtualThreshold: false,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/orgs?select=*&path=cd.root&order=code',
|
||||||
|
adaptor:
|
||||||
|
"const recursive = id => {\r\n let nodes = payload.data.items.filter(x => {\r\n return x.parent === id\r\n })\r\n return nodes.map(item => {\r\n return {\r\n ...item,\r\n label: item.name,\r\n value: `${item.id}`,\r\n children: recursive(item.id)\r\n }\r\n })\r\n}\r\nlet school = payload.data.items.find(x => x.type === 'school');\r\nreturn {\r\n ...payload,\r\n data: [{\r\n label: school.name,\r\n value: `${school.id}`,\r\n children: recursive(school.id)\r\n }]\r\n}",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
md: 9,
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
name: 'header',
|
||||||
|
type: 'wrapper',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'service',
|
||||||
|
name: 'service',
|
||||||
|
messages: {},
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/orgs/${tree}',
|
||||||
|
sendOn: 'this.tree',
|
||||||
|
adaptor:
|
||||||
|
"let role_items = [];\r\nif(payload.data.type === '')\r\nreturn {\r\n ...payload,\r\n data: {\r\n ...payload.data,\r\n role_items: payload.data.\r\n }\r\n}",
|
||||||
|
},
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
label: '部门类型',
|
||||||
|
name: 'type',
|
||||||
|
visibleOn: 'false',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
label: '部门名称',
|
||||||
|
name: 'name',
|
||||||
|
visibleOn: 'false',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'crud',
|
||||||
|
name: 'stu',
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/users_ex?and=(or(${filter}),or(code.like.*${keywords}*,name.like.*${keywords}*),role.eq.student)&org_type=eq.class&order=code',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: {\r\n ...payload.data,\r\n items: payload.data.items.map(item => {\r\n return {\r\n ...item,\r\n stu_id: item.id\r\n }\r\n })\r\n }\r\n}',
|
||||||
|
data: {
|
||||||
|
page: '$page',
|
||||||
|
perPage: '${perPage}',
|
||||||
|
},
|
||||||
|
requestAdaptor:
|
||||||
|
'api.url = api.url.replace(/and=([^&]*?)&/g, (match, p1) => {\r\n let encodeAnd = window.btoa(p1);\r\n\treturn `encodeAnd=${encodeAnd}&`;\r\n});',
|
||||||
|
sendOn: 'this.filter',
|
||||||
|
},
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'code',
|
||||||
|
type: 'text',
|
||||||
|
label: '账号',
|
||||||
|
placeholder: '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '姓名',
|
||||||
|
name: 'name',
|
||||||
|
placeholder: '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '部门',
|
||||||
|
name: 'org_name',
|
||||||
|
placeholder: '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button-group',
|
||||||
|
label: '操作',
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '查看场次',
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '场次信息',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'crud',
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/user2projects?select=*,courses(id,name),projects(id,code,name,free_schedule),att_status_text:user2project_att_status_dict_fk(dictvalue),schedule_status:user2project_schedule_status_dict_fk(dictvalue)&user_id=eq.$id&schedule_status=neq.canceled&semester_id=eq.$currentSemester&order=created_at.asc',
|
||||||
|
data: {
|
||||||
|
page: '$page',
|
||||||
|
perPage: '$perPage',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'schedule_status.dictvalue',
|
||||||
|
label: '选课状态',
|
||||||
|
type: 'plain',
|
||||||
|
placeholder: '-',
|
||||||
|
inline: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'courses.name',
|
||||||
|
label: '课程',
|
||||||
|
type: 'text',
|
||||||
|
placeholder: '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'tpl',
|
||||||
|
label: '项目',
|
||||||
|
name: 'projects.name',
|
||||||
|
placeholder: '-',
|
||||||
|
tpl: '<% if(this.projects && this.projects.free_schedule) { %>\n <span class="label label-info">自由安排</span><span><%= this.projects.name %></span>\n<% } else if(this.projects) { %>\n <span><%= this.projects.name %></span>\n<% } %>',
|
||||||
|
inline: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '考勤状态',
|
||||||
|
name: 'att_status_text.dictvalue',
|
||||||
|
placeholder: '-',
|
||||||
|
groupName: '',
|
||||||
|
remark: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'operation',
|
||||||
|
label: '操作',
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '查看',
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'crud',
|
||||||
|
syncLocation: false,
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/tasks?select=*,dict_status:dicts!task_status_fkey(*),dict_type:dicts!task_type_fkey(*)&schedule_id=eq.$schedule_id&user_id=eq.$user_id',
|
||||||
|
messages: {},
|
||||||
|
requestAdaptor: '',
|
||||||
|
adaptor: '',
|
||||||
|
},
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'content',
|
||||||
|
label: '任务',
|
||||||
|
type: 'text',
|
||||||
|
id: 'u:b7848b797bf9',
|
||||||
|
placeholder: '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'dict_type.dictvalue',
|
||||||
|
label: '类型',
|
||||||
|
type: 'text',
|
||||||
|
id: 'u:f7ed595f5c57',
|
||||||
|
placeholder: '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
wrapperComponent: '',
|
||||||
|
id: 'u:80864ebd90a9',
|
||||||
|
label: '状态',
|
||||||
|
placeholder: '-',
|
||||||
|
name: 'dict_status.dictvalue',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
bulkActions: [],
|
||||||
|
itemActions: [],
|
||||||
|
id: 'u:3458736acc74',
|
||||||
|
perPageAvailable: [10],
|
||||||
|
messages: {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 'lg',
|
||||||
|
actions: [],
|
||||||
|
closeOnEsc: true,
|
||||||
|
closeOnOutside: false,
|
||||||
|
showCloseButton: true,
|
||||||
|
id: 'u:bc2fcc411e2a',
|
||||||
|
},
|
||||||
|
size: 'xs',
|
||||||
|
level: 'primary',
|
||||||
|
closeOnEsc: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
messages: {},
|
||||||
|
syncLocation: false,
|
||||||
|
affixHeader: false,
|
||||||
|
bodyClassName: '',
|
||||||
|
className: '',
|
||||||
|
perPageAvailable: [10],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
actions: [],
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
size: 'lg',
|
||||||
|
},
|
||||||
|
level: 'primary',
|
||||||
|
size: 'xs',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
placeholder: '-',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
messages: {},
|
||||||
|
className: '',
|
||||||
|
headerToolbar: [],
|
||||||
|
md: 9,
|
||||||
|
syncLocation: false,
|
||||||
|
footerToolbar: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
wrapWithPanel: false,
|
||||||
|
reload: 'stu?perPage=${perPage}',
|
||||||
|
submitOnChange: true,
|
||||||
|
submitOnInit: false,
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
name: 'perPage',
|
||||||
|
value: '10',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: '默认',
|
||||||
|
value: '17',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '10',
|
||||||
|
value: '10',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '20',
|
||||||
|
value: '20',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '50',
|
||||||
|
value: '50',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '100',
|
||||||
|
value: '100',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '500',
|
||||||
|
value: '500',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
label: '每页显示',
|
||||||
|
mode: 'inline',
|
||||||
|
checkAll: false,
|
||||||
|
className: 'm-t-sm',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'pagination',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
perPageAvailable: '',
|
||||||
|
columnsTogglable: 'auto',
|
||||||
|
filter: {
|
||||||
|
title: '',
|
||||||
|
affixFooter: false,
|
||||||
|
actions: [],
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'input-group',
|
||||||
|
name: 'keywords',
|
||||||
|
label: '学号或姓名 ',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
placeholder: '',
|
||||||
|
inputClassName: 'b-r-none p-r-none',
|
||||||
|
name: 'keywords',
|
||||||
|
size: 'md',
|
||||||
|
clearable: true,
|
||||||
|
value: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'control',
|
||||||
|
label: '',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'submit',
|
||||||
|
level: 'primary',
|
||||||
|
actionType: 'submit',
|
||||||
|
label: '搜索',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
bulkActions: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 'xs',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
className: 'partment-grid',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
tabsMode: 'line',
|
||||||
|
tabClassName: '',
|
||||||
|
id: 'u:4f5cf5424791',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
messages: {},
|
||||||
|
bodyClassName: '',
|
||||||
|
title: '',
|
||||||
|
id: 'u:976cfa59becd',
|
||||||
|
};
|
||||||
|
|
||||||
|
export { schema };
|
||||||
1193
src/pages/schema/centre/data/template.schema.ts
Normal file
1193
src/pages/schema/centre/data/template.schema.ts
Normal file
File diff suppressed because it is too large
Load Diff
92
src/pages/schema/centre/evaluation/params.schema.ts
Normal file
92
src/pages/schema/centre/evaluation/params.schema.ts
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
const schema = {
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
api: {
|
||||||
|
method: 'patch',
|
||||||
|
url: 'rest/config?key=eq.evaluation&organization_id=eq.$centre_id',
|
||||||
|
data: {
|
||||||
|
evaluationInstruStatus: '$evaluationInstruStatus',
|
||||||
|
evaluationInstru: '$evaluationInstru',
|
||||||
|
evaluationIntroStatus: '$evaluationIntroStatus',
|
||||||
|
evaluationIntro: '$evaluationIntro',
|
||||||
|
},
|
||||||
|
dataType: 'json',
|
||||||
|
requestAdaptor:
|
||||||
|
'return {\r\n ...api,\r\n data: {\r\n value: api.data\r\n }\r\n}',
|
||||||
|
},
|
||||||
|
name: 'form',
|
||||||
|
title: '',
|
||||||
|
wrapWithPanel: true,
|
||||||
|
initApi: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/config?key=eq.evaluation&organization_id=eq.$centre_id',
|
||||||
|
adaptor:
|
||||||
|
'let item = payload.data.items[0]\r\nreturn {\r\n data: {\r\n ...item.value\r\n }\r\n}',
|
||||||
|
},
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'fieldset',
|
||||||
|
title: '评教指引及评教说明配置',
|
||||||
|
collapsable: true,
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'switch',
|
||||||
|
name: 'evaluationInstruStatus',
|
||||||
|
value: true,
|
||||||
|
option: '评教指引',
|
||||||
|
optionAtLeft: false,
|
||||||
|
trueValue: true,
|
||||||
|
falseValue: false,
|
||||||
|
onText: '开启',
|
||||||
|
offText: '关闭',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-rich-text',
|
||||||
|
label: '',
|
||||||
|
name: 'evaluationInstru',
|
||||||
|
mode: 'normal',
|
||||||
|
visibleOn: '',
|
||||||
|
clearValueOnHidden: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'switch',
|
||||||
|
option: '评教说明',
|
||||||
|
name: 'evaluationIntroStatus',
|
||||||
|
optionAtLeft: false,
|
||||||
|
trueValue: true,
|
||||||
|
falseValue: false,
|
||||||
|
value: true,
|
||||||
|
onText: '开启',
|
||||||
|
offText: '关闭',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-rich-text',
|
||||||
|
name: 'evaluationIntro',
|
||||||
|
label: '',
|
||||||
|
mode: 'normal',
|
||||||
|
visibleOn: '',
|
||||||
|
clearValueOnHidden: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
submitText: '保存',
|
||||||
|
submitOnChange: false,
|
||||||
|
submitOnInit: false,
|
||||||
|
reload: '',
|
||||||
|
affixFooter: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: 'page',
|
||||||
|
messages: {},
|
||||||
|
title: '评教参数设置',
|
||||||
|
toolbar: [
|
||||||
|
{ type: 'submit', label: '保存', level: 'primary', target: 'form' },
|
||||||
|
],
|
||||||
|
bodyClassName: '',
|
||||||
|
style: {},
|
||||||
|
subTitle: '设置评教指引、评教说明等参数',
|
||||||
|
};
|
||||||
|
|
||||||
|
export { schema };
|
||||||
789
src/pages/schema/centre/evaluation/settings.schema.ts
Normal file
789
src/pages/schema/centre/evaluation/settings.schema.ts
Normal file
@@ -0,0 +1,789 @@
|
|||||||
|
const schema = {
|
||||||
|
type: 'page',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'crud',
|
||||||
|
name: 'eval',
|
||||||
|
id: 'u:1eda9b4880ff',
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
name: 'parent_name',
|
||||||
|
label: '一级指标',
|
||||||
|
id: 'u:6dbfe25ccbea',
|
||||||
|
placeholder: '-',
|
||||||
|
quickEdit: {
|
||||||
|
mode: 'popOver',
|
||||||
|
saveImmediately: {
|
||||||
|
api: {
|
||||||
|
method: 'patch',
|
||||||
|
url: 'rest/teaching_evaluation_items/$id',
|
||||||
|
data: {
|
||||||
|
name: '$parent_name',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
type: 'input-text',
|
||||||
|
name: 'parent_name',
|
||||||
|
size: 'lg',
|
||||||
|
},
|
||||||
|
quickEditEnabledOn: '!this.parent',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'name',
|
||||||
|
type: 'text',
|
||||||
|
label: '二级指标',
|
||||||
|
id: 'u:a42f65cf3947',
|
||||||
|
placeholder: '-',
|
||||||
|
quickEdit: {
|
||||||
|
mode: 'popOver',
|
||||||
|
type: 'input-text',
|
||||||
|
label: '',
|
||||||
|
name: 'name',
|
||||||
|
saveImmediately: {
|
||||||
|
api: {
|
||||||
|
method: 'patch',
|
||||||
|
url: 'rest/teaching_evaluation_items/$id',
|
||||||
|
data: {
|
||||||
|
name: '$name',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
size: 'lg',
|
||||||
|
},
|
||||||
|
quickEditEnabledOn: 'this.parent',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'order',
|
||||||
|
label: '顺序',
|
||||||
|
type: 'tpl',
|
||||||
|
id: 'u:a617718a149f',
|
||||||
|
placeholder: '-',
|
||||||
|
tpl: '${order}',
|
||||||
|
inline: true,
|
||||||
|
quickEdit: {
|
||||||
|
type: 'input-number',
|
||||||
|
name: 'order',
|
||||||
|
label: '数字',
|
||||||
|
min: '1',
|
||||||
|
step: 1,
|
||||||
|
value: 1,
|
||||||
|
saveImmediately: {
|
||||||
|
api: {
|
||||||
|
method: 'patch',
|
||||||
|
url: 'rest/teaching_evaluation_items?id=eq.${id}',
|
||||||
|
data: {
|
||||||
|
order: '$order',
|
||||||
|
},
|
||||||
|
dataType: 'form',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mode: 'popOver',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '权重',
|
||||||
|
name: 'weight',
|
||||||
|
id: 'u:956ac49cc933',
|
||||||
|
placeholder: '-',
|
||||||
|
quickEdit: {
|
||||||
|
type: 'input-number',
|
||||||
|
name: 'weight',
|
||||||
|
label: '',
|
||||||
|
step: 0.5,
|
||||||
|
min: '0',
|
||||||
|
saveImmediately: {
|
||||||
|
api: {
|
||||||
|
method: 'patch',
|
||||||
|
url: 'rest/teaching_evaluation_items/$id',
|
||||||
|
data: {
|
||||||
|
weight: '$weight',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mode: 'popOver',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'operation',
|
||||||
|
label: '操作',
|
||||||
|
id: 'u:6a7475988e72',
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
type: 'button-group',
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '',
|
||||||
|
visibleOn: '!this.parent',
|
||||||
|
icon: 'fa fa-plus text-primary',
|
||||||
|
level: 'link',
|
||||||
|
size: 'md',
|
||||||
|
tooltip: '添加二级指标',
|
||||||
|
tooltipPlacement: 'top',
|
||||||
|
iconClassName: 'pull-left',
|
||||||
|
className: 'p-r-none p-l-none',
|
||||||
|
id: 'u:e0d17fb5cf3e',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '添加二级指标',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'rest/teaching_evaluation_items',
|
||||||
|
data: {
|
||||||
|
name: '$name',
|
||||||
|
weight: '$weight',
|
||||||
|
organization_id: '$centre_id',
|
||||||
|
semester_id: '$currentSemester',
|
||||||
|
parent: '$id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
label: '名称',
|
||||||
|
name: 'name',
|
||||||
|
mode: 'normal',
|
||||||
|
required: true,
|
||||||
|
id: 'u:6ba0f199321c',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-number',
|
||||||
|
name: 'weight',
|
||||||
|
label: '权重',
|
||||||
|
mode: 'normal',
|
||||||
|
min: '0',
|
||||||
|
step: 0.5,
|
||||||
|
required: true,
|
||||||
|
id: 'u:fa0cff8dbbc5',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:a7a2df747e8d',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'submit',
|
||||||
|
label: '提交',
|
||||||
|
primary: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
feat: 'Insert',
|
||||||
|
dsType: 'api',
|
||||||
|
onEvent: {
|
||||||
|
submitSucc: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
componentId: 'u:1eda9b4880ff',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'reload',
|
||||||
|
args: {
|
||||||
|
resetPage: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
size: 'lg',
|
||||||
|
id: 'u:18243755deb7',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'cancel',
|
||||||
|
label: '取消',
|
||||||
|
id: 'u:188cf1c021ad',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'confirm',
|
||||||
|
label: '确定',
|
||||||
|
primary: true,
|
||||||
|
id: 'u:c83910750b73',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
level: 'link',
|
||||||
|
size: 'md',
|
||||||
|
icon: 'fa fa-pencil text-info',
|
||||||
|
visibleOn: '!this.parent',
|
||||||
|
tooltip: '修改一级指标',
|
||||||
|
tooltipPlacement: 'top',
|
||||||
|
iconClassName: 'pull-left',
|
||||||
|
className: 'p-r-none p-l-none',
|
||||||
|
id: 'u:e2ca6634c8a6',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '修改一级指标',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
api: {
|
||||||
|
method: 'patch',
|
||||||
|
url: 'rest/teaching_evaluation_items/$id',
|
||||||
|
data: {
|
||||||
|
name: '$parent_name',
|
||||||
|
weight: '$weight',
|
||||||
|
},
|
||||||
|
dataType: 'json',
|
||||||
|
},
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
label: '名称',
|
||||||
|
type: 'input-text',
|
||||||
|
name: 'parent_name',
|
||||||
|
mode: 'normal',
|
||||||
|
required: true,
|
||||||
|
id: 'u:e694855bd5a0',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-number',
|
||||||
|
label: '权重',
|
||||||
|
name: 'weight',
|
||||||
|
mode: 'normal',
|
||||||
|
min: '0',
|
||||||
|
step: 0.5,
|
||||||
|
required: true,
|
||||||
|
id: 'u:6ef32f0c3c51',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:0045f9b77be4',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'submit',
|
||||||
|
label: '提交',
|
||||||
|
primary: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
feat: 'Insert',
|
||||||
|
dsType: 'api',
|
||||||
|
onEvent: {
|
||||||
|
submitSucc: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
componentId: 'u:1eda9b4880ff',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'reload',
|
||||||
|
args: {
|
||||||
|
resetPage: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
size: 'lg',
|
||||||
|
id: 'u:3e72890a4b8e',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'cancel',
|
||||||
|
label: '取消',
|
||||||
|
id: 'u:7472c80f7c68',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'confirm',
|
||||||
|
label: '确定',
|
||||||
|
primary: true,
|
||||||
|
id: 'u:d860e25841e9',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
confirmText: '确认删除"${parent_name}"?',
|
||||||
|
level: 'link',
|
||||||
|
icon: 'fa fa-times text-danger',
|
||||||
|
size: 'md',
|
||||||
|
tooltip: '删除一级指标',
|
||||||
|
tooltipPlacement: 'top',
|
||||||
|
reload: '',
|
||||||
|
visibleOn: '!this.parent && !this.children.length',
|
||||||
|
iconClassName: 'pull-left',
|
||||||
|
className: 'p-r-none p-l-none',
|
||||||
|
id: 'u:967e36c71712',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
outputVar: 'responseResult',
|
||||||
|
actionType: 'ajax',
|
||||||
|
options: {},
|
||||||
|
api: {
|
||||||
|
url: 'rest/teaching_evaluation_items/$id',
|
||||||
|
method: 'delete',
|
||||||
|
requestAdaptor: '',
|
||||||
|
adaptor: '',
|
||||||
|
messages: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentId: 'u:1eda9b4880ff',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'reload',
|
||||||
|
args: {
|
||||||
|
resetPage: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
level: 'link',
|
||||||
|
size: 'md',
|
||||||
|
icon: 'fa fa-pencil text-info',
|
||||||
|
visibleOn: 'this.parent',
|
||||||
|
tooltip: '修改二级指标',
|
||||||
|
tooltipPlacement: 'top',
|
||||||
|
className: 'p-r-none p-l-none',
|
||||||
|
iconClassName: 'pull-left',
|
||||||
|
id: 'u:8290e35c33ea',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '修改二级指标',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
api: {
|
||||||
|
method: 'patch',
|
||||||
|
url: 'rest/teaching_evaluation_items/$id',
|
||||||
|
data: {
|
||||||
|
name: '$name',
|
||||||
|
weight: '$weight',
|
||||||
|
parent: '$parent',
|
||||||
|
},
|
||||||
|
dataType: 'json',
|
||||||
|
},
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
label: '名称',
|
||||||
|
type: 'input-text',
|
||||||
|
name: 'name',
|
||||||
|
mode: 'normal',
|
||||||
|
required: true,
|
||||||
|
id: 'u:c2480af665ff',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-number',
|
||||||
|
label: '权重',
|
||||||
|
name: 'weight',
|
||||||
|
mode: 'normal',
|
||||||
|
min: '0',
|
||||||
|
step: 0.5,
|
||||||
|
required: true,
|
||||||
|
id: 'u:b401731a558d',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
label: '一级指标',
|
||||||
|
name: 'parent',
|
||||||
|
mode: 'normal',
|
||||||
|
options: [],
|
||||||
|
checkAll: false,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/teaching_evaluation_items?parent=is.null&organization_id=eq.$centre_id&semester_id=eq.$currentSemester&order=order',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload.data,\r\n items: payload.data.items.map(item => {\r\n return {\r\n label: item.name,\r\n value: item.id\r\n }\r\n })\r\n}',
|
||||||
|
},
|
||||||
|
searchable: true,
|
||||||
|
required: true,
|
||||||
|
id: 'u:d1ed468a2aa3',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:d0af5e81cfa8',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'submit',
|
||||||
|
label: '提交',
|
||||||
|
primary: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
feat: 'Insert',
|
||||||
|
dsType: 'api',
|
||||||
|
onEvent: {
|
||||||
|
submitSucc: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
componentId: 'u:1eda9b4880ff',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'reload',
|
||||||
|
args: {
|
||||||
|
resetPage: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
size: 'lg',
|
||||||
|
id: 'u:44a6ba40d2f2',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'cancel',
|
||||||
|
label: '取消',
|
||||||
|
id: 'u:05a728e1cf94',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'confirm',
|
||||||
|
label: '确定',
|
||||||
|
primary: true,
|
||||||
|
id: 'u:8bed7ea1617c',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
confirmText: '确认删除"${name}"?',
|
||||||
|
level: 'link',
|
||||||
|
icon: 'fa fa-times text-danger',
|
||||||
|
size: 'md',
|
||||||
|
tooltip: '删除二级指标',
|
||||||
|
tooltipPlacement: 'top',
|
||||||
|
reload: '',
|
||||||
|
visibleOn: 'this.parent',
|
||||||
|
iconClassName: 'pull-left',
|
||||||
|
className: 'p-r-none p-l-none',
|
||||||
|
id: 'u:46e8dd7835fd',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
outputVar: 'responseResult',
|
||||||
|
actionType: 'ajax',
|
||||||
|
options: {},
|
||||||
|
api: {
|
||||||
|
url: 'rest/teaching_evaluation_items/$id',
|
||||||
|
method: 'delete',
|
||||||
|
requestAdaptor: '',
|
||||||
|
adaptor: '',
|
||||||
|
messages: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentId: 'u:1eda9b4880ff',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'reload',
|
||||||
|
args: {
|
||||||
|
resetPage: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
label: '操作',
|
||||||
|
id: 'u:ae8cc0b046b6',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
messages: {},
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/teaching_evaluation_items?semester_id=eq.$currentSemester&organization_id=eq.$centre_id&order=order',
|
||||||
|
data: null,
|
||||||
|
requestAdaptor: '',
|
||||||
|
adaptor:
|
||||||
|
'let evaluations = []\r\nlet parents = payload.data.items.filter(item => !item.parent)\r\n\r\nparents.length && parents.forEach((parent, index) => {\r\n evaluations.push({\r\n id: parent.id,\r\n order: parent.order,\r\n parent_name: parent.name,\r\n weight: parent.weight,\r\n parent: parent.parent,\r\n children: payload.data.items\r\n .filter(item => item.parent === parent.id)\r\n })\r\n})\r\n\r\nreturn {\r\n ...payload,\r\n data: {\r\n ...payload.data,\r\n items: evaluations\r\n }\r\n}',
|
||||||
|
sendOn: '',
|
||||||
|
},
|
||||||
|
syncLocation: false,
|
||||||
|
headerToolbar: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
align: 'right',
|
||||||
|
icon: '',
|
||||||
|
level: 'primary',
|
||||||
|
label: '添加一级指标',
|
||||||
|
id: 'u:37f0878b29a0',
|
||||||
|
reload: '',
|
||||||
|
tpl: '内容',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '添加一级指标',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'rest/teaching_evaluation_items',
|
||||||
|
data: {
|
||||||
|
name: '$name',
|
||||||
|
weight: '$weight',
|
||||||
|
organization_id: '$centre_id',
|
||||||
|
semester_id: '$currentSemester',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
label: '名称',
|
||||||
|
name: 'name',
|
||||||
|
required: true,
|
||||||
|
mode: 'normal',
|
||||||
|
id: 'u:53e7e8e5c2f6',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-number',
|
||||||
|
name: 'weight',
|
||||||
|
label: '权重',
|
||||||
|
mode: 'normal',
|
||||||
|
required: true,
|
||||||
|
min: '0',
|
||||||
|
step: 0.5,
|
||||||
|
id: 'u:a85fdbfc8915',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:4f356ae00643',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'submit',
|
||||||
|
label: '提交',
|
||||||
|
primary: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
feat: 'Insert',
|
||||||
|
dsType: 'api',
|
||||||
|
onEvent: {
|
||||||
|
submitSucc: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
componentId: 'u:1eda9b4880ff',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'reload',
|
||||||
|
args: {
|
||||||
|
resetPage: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
size: 'lg',
|
||||||
|
id: 'u:bdb5abe2835a',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'cancel',
|
||||||
|
label: '取消',
|
||||||
|
id: 'u:0b55901a86eb',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'confirm',
|
||||||
|
label: '确定',
|
||||||
|
primary: true,
|
||||||
|
id: 'u:6dbf2b39f297',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '指定学期导入',
|
||||||
|
align: 'right',
|
||||||
|
level: 'primary',
|
||||||
|
visibleOn: '',
|
||||||
|
className: '',
|
||||||
|
id: 'u:595e4f3e93ab',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '指定学期',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'rest/rpc/create_evaluation_items_from_history',
|
||||||
|
data: {
|
||||||
|
organization_id: '$centre_id',
|
||||||
|
semester_id: '$semester_id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
target: '',
|
||||||
|
name: 'form',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
actionType: 'reload',
|
||||||
|
target: 'recognize',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
label: '学期',
|
||||||
|
type: 'select',
|
||||||
|
name: 'semester_id',
|
||||||
|
mode: 'inline',
|
||||||
|
options: [],
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/semesters?is_open=is.false&order=code',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: {\r\n ...payload.data,\r\n items: payload.data.items.map(item => {\r\n return {\r\n label: item.name,\r\n value: item.id\r\n }\r\n })\r\n }\r\n}',
|
||||||
|
requestAdaptor: '',
|
||||||
|
},
|
||||||
|
size: 'md',
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
checkAll: false,
|
||||||
|
clearable: false,
|
||||||
|
searchable: true,
|
||||||
|
id: 'u:7ee00833ea34',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:551a790ac5aa',
|
||||||
|
feat: 'Insert',
|
||||||
|
dsType: 'api',
|
||||||
|
onEvent: {
|
||||||
|
submitSucc: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
componentId: 'u:1eda9b4880ff',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'reload',
|
||||||
|
args: {
|
||||||
|
resetPage: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
size: 'sm',
|
||||||
|
id: 'u:8d46598e4801',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'cancel',
|
||||||
|
label: '取消',
|
||||||
|
id: 'u:39cbcc618226',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'confirm',
|
||||||
|
label: '确定',
|
||||||
|
primary: true,
|
||||||
|
id: 'u:cab0fce5d690',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
footerToolbar: [],
|
||||||
|
perPageAvailable: [10, 20, 30, 40, 50],
|
||||||
|
filter: null,
|
||||||
|
bulkActions: [],
|
||||||
|
className: '',
|
||||||
|
md: 9,
|
||||||
|
columnsTogglable: false,
|
||||||
|
quickSaveItemApi: '',
|
||||||
|
hideQuickSaveBtn: true,
|
||||||
|
visibleOn: '',
|
||||||
|
perPage: null,
|
||||||
|
loadDataOnce: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:23e12f269e33',
|
||||||
|
messages: {},
|
||||||
|
title: '',
|
||||||
|
bodyClassName: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
export { schema };
|
||||||
690
src/pages/schema/centre/evaluation/stat.schema.ts
Normal file
690
src/pages/schema/centre/evaluation/stat.schema.ts
Normal file
@@ -0,0 +1,690 @@
|
|||||||
|
const schema = {
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'tabs',
|
||||||
|
className: '',
|
||||||
|
tabs: [
|
||||||
|
{
|
||||||
|
title: '日程一览',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
className: '',
|
||||||
|
submitOnChange: true,
|
||||||
|
submitOnInit: true,
|
||||||
|
reload:
|
||||||
|
'manage_loc?course_id=$course_id&project_id=$project_id&teacher_id=$teacher_id&location_id=$location_id&date=$date&no_tch=$no_tch&public=$public&semesterSelect=$semesterSelect',
|
||||||
|
initApi: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/users?role=eq.teacher&id=eq.${user.id}&order=code',
|
||||||
|
requestAdaptor: '',
|
||||||
|
adaptor:
|
||||||
|
"if (payload.data.items.length !== 0) {\r\n return {\r\n teacher_id: 'eq.'.concat(payload.data.items[0].id)\r\n }\r\n} else {\r\n return {}\r\n}",
|
||||||
|
},
|
||||||
|
wrapWithPanel: false,
|
||||||
|
mode: 'inline',
|
||||||
|
name: 'filter',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'group',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
label: '历史',
|
||||||
|
name: 'semesterSelect',
|
||||||
|
options: [],
|
||||||
|
checkAll: false,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/semesters?order=is_open.desc,since.desc',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: {\r\n ...payload.data,\r\n items: payload.data.items.map(item => {\r\n return {\r\n label: item.name,\r\n value: item.id\r\n }\r\n })\r\n }\r\n}',
|
||||||
|
},
|
||||||
|
searchable: true,
|
||||||
|
clearable: false,
|
||||||
|
mode: 'inline',
|
||||||
|
size: 'md',
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
id: 'u:a4b2e9a131fa',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '课程',
|
||||||
|
type: 'select',
|
||||||
|
name: 'course_id',
|
||||||
|
mode: 'inline',
|
||||||
|
clearable: true,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/courses?organization_id=eq.$centre_id&semester_id=eq.$semesterSelect&order=code',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: payload.data.items.map(item => {\r\n return {\r\n label: `${item.name}(${item.code})`,\r\n value: "eq.".concat(item.id)\r\n }\r\n })\r\n}',
|
||||||
|
},
|
||||||
|
checkAll: false,
|
||||||
|
size: 'md',
|
||||||
|
searchable: true,
|
||||||
|
className: 'm-l-sm',
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
id: 'u:22532e0d2a66',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
label: '实验',
|
||||||
|
name: 'project_id',
|
||||||
|
mode: 'inline',
|
||||||
|
clearable: true,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/projects?select=*,course2projects(*)&organization_id=eq.$centre_id&semester_id=eq.$semesterSelect&course2projects.course_id=$course_id&order=code',
|
||||||
|
adaptor:
|
||||||
|
"return {\r\n ...payload,\r\n data: {\r\n ...payload.data,\r\n items: payload.data.items.filter(\r\n f => f.course2projects.length > 0\r\n ).map(item => {\r\n return {\r\n label: item.name,\r\n value: 'eq.'.concat(item.id)\r\n }\r\n })\r\n }\r\n}",
|
||||||
|
requestAdaptor:
|
||||||
|
'if (api.query.course2projects.course_id === \'\') {\r\n api.url = api.url.replace("&course2projects[course_id]=", "")\r\n}\r\n\r\nreturn api',
|
||||||
|
},
|
||||||
|
checkAll: false,
|
||||||
|
size: 'md',
|
||||||
|
searchable: true,
|
||||||
|
className: 'm-l-sm',
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
id: 'u:cf571eb6cc1a',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:0cf1ac6473cc',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'group',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'input-date-range',
|
||||||
|
label: '日期',
|
||||||
|
name: 'date',
|
||||||
|
mode: 'inline',
|
||||||
|
clearable: true,
|
||||||
|
value: '',
|
||||||
|
format: 'YYYY-MM-DD',
|
||||||
|
ranges:
|
||||||
|
'yesterday,today,7daysago,prevweek,thismonth,prevmonth,prevquarter',
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
id: 'u:b78bf613761a',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
label: '地点',
|
||||||
|
name: 'location_id',
|
||||||
|
mode: 'inline',
|
||||||
|
clearable: true,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/locations?organization_id=eq.$centre_id&order=code',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: payload.data.items.map(item => {\r\n return {\r\n label: item.name,\r\n value: "eq.".concat(item.id)\r\n }\r\n })\r\n}',
|
||||||
|
},
|
||||||
|
checkAll: false,
|
||||||
|
size: 'md',
|
||||||
|
searchable: true,
|
||||||
|
className: 'm-l-sm',
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
id: 'u:d90502be2317',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '教师',
|
||||||
|
type: 'select',
|
||||||
|
name: 'teacher_id',
|
||||||
|
mode: 'inline',
|
||||||
|
clearable: true,
|
||||||
|
checkAll: false,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/users?role=eq.teacher&order=code',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: payload.data.items.map(item => {\r\n return {\r\n label: `${item.name}(${item.code})`,\r\n value: "eq.".concat(item.id)\r\n }\r\n })\r\n}',
|
||||||
|
},
|
||||||
|
size: 'md',
|
||||||
|
searchable: true,
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
className: 'm-l-sm',
|
||||||
|
id: 'u:2fd7d9613116',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:9df1f6742c55',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'group',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'switch',
|
||||||
|
name: 'no_tch',
|
||||||
|
option: '仅显示无教师场次',
|
||||||
|
mode: 'inline',
|
||||||
|
optionAtLeft: false,
|
||||||
|
trueValue: 1,
|
||||||
|
falseValue: 0,
|
||||||
|
value: 0,
|
||||||
|
disabledOn: 'this.teacher_id',
|
||||||
|
id: 'u:16519e5c1c12',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'switch',
|
||||||
|
name: 'public',
|
||||||
|
option: '仅显示公共场次',
|
||||||
|
mode: 'inline',
|
||||||
|
optionAtLeft: false,
|
||||||
|
trueValue: 1,
|
||||||
|
falseValue: 0,
|
||||||
|
value: 0,
|
||||||
|
disabledOn: 'this.course_id',
|
||||||
|
inputClassName: 'm-l-sm',
|
||||||
|
id: 'u:0d1445244f47',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:6add1eda4c2a',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:42c847232809',
|
||||||
|
},
|
||||||
|
{ type: 'divider', lineStyle: 'solid', id: 'u:3eb06bbf6fa8' },
|
||||||
|
{
|
||||||
|
type: 'crud',
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/teaching_evaluation_stats?select=*?organization_id=eq.$centre_id&semester_id=eq.$semesterSelect&is_publish=is.true&order=project_name,date,teacher_name',
|
||||||
|
data: { '&': '$$', page: '$page', perPage: '$perPage' },
|
||||||
|
requestAdaptor:
|
||||||
|
"if (api.query.semesterSelect) {\r\n api.url = api.url.replace(/&semesterSelect=\\d*/g, '')\r\n api.url = api.url.replace(/(?<=semester_id=eq\\.)\\d*(?=&)/g, api.query.semesterSelect)\r\n} else {\r\n api.url = api.url.replace(/&semesterSelect=/g, '')\r\n}\r\nif (api.body.course_id === '') {\r\n api.url = api.url.replace(/&course_id=/g, '')\r\n}\r\nif (api.body.project_id === '') {\r\n api.url = api.url.replace(/&project_id=/g, '')\r\n}\r\nif (api.body.date === '') {\r\n api.url = api.url.replace(/&date=/g, '')\r\n}\r\nif (api.body.location_id === '') {\r\n api.url = api.url.replace(/&location_id=/g, '')\r\n}\r\nif (api.body.teacher_id === '') {\r\n api.url = api.url.replace(/&teacher_id=/g, '')\r\n}\r\nif (api.body.no_tch === 0) {\r\n api.url = api.url.replace(/&no_tch=0/g, '')\r\n}\r\nif (api.body.public === 0) {\r\n api.url = api.url.replace(/&public=0/g, '')\r\n}\r\nconst pattern = /(?:date=)(\\d+-\\d+-\\d+)%2C(\\d+-\\d+-\\d+)/g\r\nconst result = pattern.exec(api.url)\r\nif (result && result[1] === result[2]) {\r\n api.url = api.url.replace(result[0], 'date=eq.'.concat(result[1]))\r\n} else if (result) {\r\n api.url = api.url.replace(result[0], 'date=gte.'.concat(result[1], '&date=lte.', result[2]))\r\n}\r\nconst is_no_tch = /no_tch=1/g.test(api.url)\r\nconst has_teacher = /teacher_id=.+?(?=&)/g.test(api.url)\r\nif (is_no_tch && has_teacher) {\r\n const teacher = /teacher_id=.+?(?=&)/g.exec(api.url)\r\n api.url = api.url.replace(teacher, 'or=('.concat(teacher, ',teacher_id.is.null)')).replace('teacher_id=', 'teacher_id.')\r\n api.url = api.url.replace(/no_tch=1/g, '')\r\n} else if (is_no_tch && !has_teacher) {\r\n api.url = api.url.replace(/no_tch=1/g, 'teacher_id=is.null')\r\n}\r\nconst is_public = /public=1/g.test(api.url)\r\nconst has_course = /course_id=.+?(?=&)/g.test(api.url)\r\nif (is_public && has_course) {\r\n const course = /course_id=.+?(?=&)/g.exec(api.url)\r\n api.url = api.url.replace(course, 'or=('.concat(course, ',course_id.is.null)')).replace('course_id=', 'course_id.')\r\n api.url = api.url.replace(/public=1/g, '')\r\n} else if (is_public && !has_course) {\r\n api.url = api.url.replace(/public=1/g, 'course_id=is.null')\r\n}\r\nreturn {\r\n ...api\r\n}",
|
||||||
|
adaptor:
|
||||||
|
"let supportDateTimeFormat = typeof(Intl.DateTimeFormat) === 'function';\r\npayload.data.items.forEach(item => {\r\n item.day = supportDateTimeFormat ? `${item.date}(${new Intl.DateTimeFormat('zh-CN', { weekday: 'short'}).format(new Date(item.date))})` : item.date;\r\n item.stu_title = item.project_name.concat(\r\n ' :: ', item.date, ' ', item.period_name,\r\n ' :: ', item.location_name,\r\n ' :: ', item.teacher_name ? item.teacher_name : '无教师认领'\r\n )\r\n})\r\n\r\nreturn {\r\n ...payload\r\n}",
|
||||||
|
},
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
label: '实验',
|
||||||
|
type: 'tpl',
|
||||||
|
placeholder: '-',
|
||||||
|
tpl: '<% if(!this.course_id) { %>\n <span class="label label-info">公共</span><span> <%= this.project_name %> <span>\n<% } else {%>\n <span> <%= this.project_name %> <span>\n<% } %>',
|
||||||
|
inline: false,
|
||||||
|
id: 'u:821411c19e45',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'day',
|
||||||
|
label: '日期',
|
||||||
|
type: 'text',
|
||||||
|
placeholder: '-',
|
||||||
|
id: 'u:65690067149b',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '节次',
|
||||||
|
name: 'period_name',
|
||||||
|
placeholder: '-',
|
||||||
|
id: 'u:2aed39988a12',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '地点',
|
||||||
|
name: 'location_name',
|
||||||
|
placeholder: '-',
|
||||||
|
id: 'u:9298ea2c6eb8',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'tpl',
|
||||||
|
tpl: '${teacher_name}',
|
||||||
|
inline: false,
|
||||||
|
label: '教师姓名',
|
||||||
|
name: 'teacher_name',
|
||||||
|
placeholder: '-',
|
||||||
|
id: 'u:1b5d4fe03c4f',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'tpl',
|
||||||
|
tpl: '${teacher_code}',
|
||||||
|
inline: false,
|
||||||
|
label: '教师工号',
|
||||||
|
name: 'teacher_code',
|
||||||
|
placeholder: '-',
|
||||||
|
id: 'u:01a76262c44b',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'tpl',
|
||||||
|
tpl: '<% if (data.participation_count<1) { %> \n<span>暂无</span>\n<% } else { %>\n<%= data.evaluation_rating %>\n<% } %>',
|
||||||
|
inline: false,
|
||||||
|
label: '统计总分',
|
||||||
|
name: 'evaluation_rating',
|
||||||
|
placeholder: '-',
|
||||||
|
id: 'u:01b6021e08ff',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'tpl',
|
||||||
|
tpl: '${participation_count}',
|
||||||
|
inline: false,
|
||||||
|
label: '学生评价人数',
|
||||||
|
name: 'participation_count',
|
||||||
|
placeholder: '-',
|
||||||
|
id: 'u:fb9b688b6471',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'tpl',
|
||||||
|
tpl: '${current_student_number}',
|
||||||
|
inline: false,
|
||||||
|
label: '总选课人数',
|
||||||
|
name: 'current_student_number',
|
||||||
|
placeholder: '-',
|
||||||
|
id: 'u:10215551a08f',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'tpl',
|
||||||
|
tpl: '${participation_rating}',
|
||||||
|
inline: false,
|
||||||
|
label: '参评率',
|
||||||
|
name: 'participation_rating',
|
||||||
|
id: 'u:c3abec775099',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'operation',
|
||||||
|
label: '操作',
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
label: '评教明细',
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '评教明细',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'grid',
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
xs: 5,
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
wrapWithPanel: false,
|
||||||
|
submitOnChange: true,
|
||||||
|
reload:
|
||||||
|
'evaluation?selected_user=$selected_user',
|
||||||
|
name: 'filter',
|
||||||
|
debug: false,
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'switch',
|
||||||
|
name: 'open',
|
||||||
|
option: '显示姓名',
|
||||||
|
optionAtLeft: false,
|
||||||
|
trueValue: true,
|
||||||
|
falseValue: false,
|
||||||
|
value: false,
|
||||||
|
mode: 'normal',
|
||||||
|
submitOnChange: false,
|
||||||
|
id: 'u:ae62dc94f85c',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '',
|
||||||
|
type: 'input-tree',
|
||||||
|
name: 'selected_user',
|
||||||
|
mode: 'inline',
|
||||||
|
size: 'lg',
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/user2projects?select=*,users:users!user2project_student_id_fkey(*)&schedule_id=eq.$schedule_id&schedule_status=eq.elected&open=$open',
|
||||||
|
adaptor:
|
||||||
|
"return {\r\n ...payload,\r\n data: {\r\n ...payload.data,\r\n items: payload.data.items.map((item, index) => {\r\n let temp = null\r\n\r\n if ((index + 1).toString().length === 1) {\r\n temp = '00' + (index + 1)\r\n } else if ((index + 1).toString().length === 2) {\r\n temp = '0' + (index + 1)\r\n } else {\r\n temp = '' + (index + 1)\r\n }\r\n\r\n return {\r\n label: item.users.name\r\n ? '' + temp + ' - 学号: ' + item.users.code + ' - 姓名: ' + item.users.name\r\n : '' + temp + ' - 学号: xxx - 姓名: xxx',\r\n value: item.users.id\r\n }\r\n })\r\n }\r\n}",
|
||||||
|
data: null,
|
||||||
|
requestAdaptor:
|
||||||
|
"if (api.query.open) {\r\n api.url = api.url.replace('&open=true', '')\r\n} else {\r\n api.url = api.url.replace('&open=false', '')\r\n api.url = api.url.replace('%2Cusers%3Ausers%21user2project_student_id_fkey%28%2A%29', '%2Cusers%3Ausers%21user2project_student_id_fkey%28id%29')\r\n}",
|
||||||
|
sendOn: '',
|
||||||
|
},
|
||||||
|
inputClassName: 'evaluation-height',
|
||||||
|
className: '',
|
||||||
|
labelClassName: '',
|
||||||
|
id: 'u:2234b8e979fc',
|
||||||
|
multiple: false,
|
||||||
|
enableNodePath: false,
|
||||||
|
hideRoot: true,
|
||||||
|
showIcon: true,
|
||||||
|
initiallyOpen: true,
|
||||||
|
virtualThreshold: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:f15b97a9e90e',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
md: 4,
|
||||||
|
id: 'u:f5120659ae2f',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'crud',
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/user2projects?select=*,teaching_evaluations(*,teaching_evaluation_items(*)),teaching_evaluation_message(content)&schedule_id=eq.$schedule_id&user_id=eq.$selected_user&schedule_status=eq.elected',
|
||||||
|
sendOn: 'this.selected_user',
|
||||||
|
adaptor:
|
||||||
|
'let evaluations = []\r\n\r\npayload.data.items[0].teaching_evaluations\r\n .filter(item => !item.teaching_evaluation_items.parent)\r\n .sort((a, b) => {\r\n return a.teaching_evaluation_items.order - b.teaching_evaluation_items.order\r\n })\r\n .forEach(parent => {\r\n evaluations.push({\r\n ...parent,\r\n parent_name: parent.teaching_evaluation_items.name\r\n })\r\n payload.data.items[0].teaching_evaluations\r\n .filter(item => item.teaching_evaluation_items.parent\r\n === parent.teaching_evaluation_items.id)\r\n .sort((a, b) => {\r\n return a.teaching_evaluation_items.order - b.teaching_evaluation_items.order\r\n })\r\n .forEach(item => evaluations.push({\r\n ...item,\r\n child_name: item.teaching_evaluation_items.name\r\n }))\r\n })\r\n\r\nconsole.log(payload.data.items[0].teaching_evaluation_message[0]);return {\r\n ...payload,\r\n data: {\r\n ...payload.data,\r\n content:payload.data.items[0].teaching_evaluation_message[0]?payload.data.items[0].teaching_evaluation_message[0].content:null, items: evaluations\r\n }\r\n}\r\n',
|
||||||
|
requestAdaptor: '',
|
||||||
|
},
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'parent_name',
|
||||||
|
label: '一级指标',
|
||||||
|
type: 'text',
|
||||||
|
id: 'u:b0fbb3e1005c',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'child_name',
|
||||||
|
label: '二级指标',
|
||||||
|
type: 'text',
|
||||||
|
id: 'u:cf4a41c690ef',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'evaluation_rating',
|
||||||
|
label: '评分',
|
||||||
|
type: 'text',
|
||||||
|
id: 'u:15f856dabafe',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
bulkActions: [],
|
||||||
|
itemActions: [],
|
||||||
|
perPageAvailable: [10],
|
||||||
|
messages: {},
|
||||||
|
headerToolbar: [
|
||||||
|
{
|
||||||
|
type: 'tpl',
|
||||||
|
tpl: '${stu_title}',
|
||||||
|
id: 'u:6ee9e9f6eea1',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
footerToolbar: [
|
||||||
|
{
|
||||||
|
type: 'tpl',
|
||||||
|
tpl: '评语:${content}',
|
||||||
|
id: 'u:6ee9e9f6eea1',
|
||||||
|
visibleOn: 'this.content'
|
||||||
|
},
|
||||||
|
],
|
||||||
|
syncLocation: false,
|
||||||
|
name: 'evaluation',
|
||||||
|
affixHeader: false,
|
||||||
|
id: 'u:9c49baa041b9',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
md: 8,
|
||||||
|
id: 'u:65c044dae897',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:9a86c3778456',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
actions: [],
|
||||||
|
data: null,
|
||||||
|
size: 'lg',
|
||||||
|
closeOnOutside: false,
|
||||||
|
bodyClassName: '',
|
||||||
|
id: 'u:43821eb65ad8',
|
||||||
|
},
|
||||||
|
level: 'primary',
|
||||||
|
size: 'xs',
|
||||||
|
id: 'u:bda614e0a3f8',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:2b35aaf1e56c',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
bulkActions: [],
|
||||||
|
itemActions: [],
|
||||||
|
syncLocation: false,
|
||||||
|
headerToolbar: [
|
||||||
|
{
|
||||||
|
type: 'export-excel',
|
||||||
|
label: '导出',
|
||||||
|
icon: 'fa fa-download',
|
||||||
|
level: 'primary',
|
||||||
|
align: 'right',
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/teaching_evaluation_stats?organization_id=eq.$centre_id&semester_id=eq.$semesterSelect&is_publish=is.true&order=project_name,date,teacher_name',
|
||||||
|
dataType: 'form',
|
||||||
|
data: { semesterSelect: '$semesterSelect' },
|
||||||
|
requestAdaptor:
|
||||||
|
"if (api.query.semesterSelect) {\r\n api.url = api.url.replace(/&semesterSelect=\\d*/g, '')\r\n api.url = api.url.replace(/(?<=semester_id=eq\\.)\\d*(?=&)/g, api.query.semesterSelect)\r\n} else {\r\n api.url = api.url.replace(/&semesterSelect=/g, '')\r\n}\r\n\r\nreturn {\r\n ...api\r\n}",
|
||||||
|
adaptor:
|
||||||
|
'let columns = [{\r\n "name": "project_name",\r\n "label": "实验" },\r\n {\r\n "name": "date",\r\n "label": "日期" },\r\n {\r\n "name": "teacher_name",\r\n "label": "教师姓名"\r\n },\r\n {\r\n "name": "teacher_code",\r\n "label": "教师工号"\r\n },\r\n {\r\n "name": "evaluation_rating",\r\n "label": "总计总分"\r\n },\r\n {\r\n "name": "participation_count",\r\n "label": "学生评价人数"\r\n },\r\n {\r\n "name": "current_student_number",\r\n "label": "总选课人数"\r\n },\r\n {\r\n "name": "participation_rating",\r\n "label": "参评率"\r\n }];\r\nreturn {\r\n ...payload,\r\n data: {\r\n items: payload.data.items,\r\n columns: columns\r\n }\r\n}',
|
||||||
|
},
|
||||||
|
filename: '评教统计',
|
||||||
|
id: 'u:1b59142be0d3',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
name: 'manage_loc',
|
||||||
|
perPageAvailable: [10, 20, 30, 40, 50],
|
||||||
|
messages: {},
|
||||||
|
id: 'u:367dac93b9ef',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
className: 'p-t-none',
|
||||||
|
id: 'u:804603aed3fd',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '自由安排',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'crud',
|
||||||
|
columns: [
|
||||||
|
{ type: 'text', label: '编号', name: 'code' },
|
||||||
|
{ name: 'name', type: 'text', label: '课程' },
|
||||||
|
{
|
||||||
|
type: 'button-group',
|
||||||
|
label: '操作',
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '查看项目',
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '项目信息',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'crud',
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/course2projects?select=*,projects(*)&course_id=eq.$id',
|
||||||
|
data: { page: '$page', perPage: '$perPage' },
|
||||||
|
adaptor:
|
||||||
|
'let free, not_free\r\nfree = payload.data.items.filter(\r\n item => item.projects.free_schedule\r\n ).sort(\r\n (a, b) => a.projects.code.localeCompare(b.projects.code)\r\n )\r\nnot_free = payload.data.items.filter(\r\n item => !item.projects.free_schedule\r\n ).sort(\r\n (a, b) => a.projects.code.localeCompare(b.projects.code)\r\n )\r\nreturn {\r\n ...payload,\r\n data: {\r\n ...payload.data,\r\n items: not_free.concat(free)\r\n }\r\n}',
|
||||||
|
},
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'projects.code',
|
||||||
|
label: '编号',
|
||||||
|
type: 'text',
|
||||||
|
placeholder: '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'projects.name',
|
||||||
|
label: '项目',
|
||||||
|
type: 'tpl',
|
||||||
|
placeholder: '-',
|
||||||
|
tpl: '<% if(this.projects && this.projects.free_schedule) { %>\n <span class="label label-info">自由安排</span><span><%= this.projects.name %></span>\n<% } else if(this.projects) { %>\n <span><%= this.projects.name %></span>\n<% } %>',
|
||||||
|
inline: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button-group',
|
||||||
|
label: '操作',
|
||||||
|
placeholder: '-',
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '评教明细',
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '评教明细',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'grid',
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'filter',
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
controls: [
|
||||||
|
{
|
||||||
|
type: 'switch',
|
||||||
|
name: 'open',
|
||||||
|
option: '显示姓名',
|
||||||
|
optionAtLeft: false,
|
||||||
|
trueValue: true,
|
||||||
|
falseValue: false,
|
||||||
|
value: false,
|
||||||
|
mode: 'inline',
|
||||||
|
submitOnChange: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '',
|
||||||
|
type: 'tree',
|
||||||
|
name: 'selected_user',
|
||||||
|
options: [],
|
||||||
|
mode: 'inline',
|
||||||
|
size: 'md',
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/user2projects?select=*,users:users!user2project_student_id_fkey(*)&schedule_id=eq.$id&schedule_status=eq.elected&open=$open',
|
||||||
|
adaptor:
|
||||||
|
"return {\r\n ...payload,\r\n data: {\r\n ...payload.data,\r\n items: payload.data.items.map(item => {\r\n return {\r\n label: item.users.name ? item.users.name : 'xxx',\r\n value: item.users.id\r\n }\r\n })\r\n }\r\n}",
|
||||||
|
data: null,
|
||||||
|
requestAdaptor:
|
||||||
|
"if (api.query.open) {\r\n api.url = api.url.replace('&open=true', '')\r\n} else {\r\n api.url = api.url.replace('&open=false', '')\r\n api.url = api.url.replace('%2Cusers%3Ausers%21user2project_student_id_fkey%28%2A%29', '%2Cusers%3Ausers%21user2project_student_id_fkey%28id%29')\r\n}",
|
||||||
|
sendOn: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
wrapWithPanel: false,
|
||||||
|
submitOnChange: true,
|
||||||
|
xs: 4,
|
||||||
|
reload:
|
||||||
|
'evaluation?selected_user=$selected_user',
|
||||||
|
debug: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'evaluation',
|
||||||
|
type: 'crud',
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/user2projects?select=*,teaching_evaluations(*,teaching_evaluation_items(*)),teaching_evaluation_message(content)&project_id=eq.$id&user_id=eq.$selected_user&schedule_status=eq.free_schedule',
|
||||||
|
sendOn: 'this.selected_user',
|
||||||
|
adaptor:
|
||||||
|
'let evaluations = []\r\n\r\npayload.data.items[0].teaching_evaluations\r\n .filter(item => !item.teaching_evaluation_items.parent)\r\n .forEach(parent => {\r\n evaluations.push({\r\n ...parent,\r\n parent_name: parent.teaching_evaluation_items.name\r\n })\r\n payload.data.items[0].teaching_evaluations\r\n .filter(item => item.teaching_evaluation_items.parent\r\n === parent.teaching_evaluation_items.id)\r\n .forEach(item => evaluations.push({\r\n ...item,\r\n child_name: item.teaching_evaluation_items.name\r\n }))\r\n })\r\n\r\nreturn {\r\n ...payload,\r\n data: {\r\n ...payload.data,\r\n items: evaluations\r\n }\r\n}\r\n',
|
||||||
|
requestAdaptor: '',
|
||||||
|
},
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'parent_name',
|
||||||
|
label: '一级指标',
|
||||||
|
type: 'text',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'child_name',
|
||||||
|
label: '二级指标',
|
||||||
|
type: 'text',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'evaluation_rating',
|
||||||
|
label: '评分',
|
||||||
|
type: 'text',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
bulkActions: [],
|
||||||
|
itemActions: [],
|
||||||
|
perPageAvailable: [10],
|
||||||
|
messages: {},
|
||||||
|
syncLocation: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
actions: [],
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
data: null,
|
||||||
|
size: 'lg',
|
||||||
|
},
|
||||||
|
size: 'xs',
|
||||||
|
level: 'primary',
|
||||||
|
visibleOn: 'this.projects.free_schedule',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
messages: {},
|
||||||
|
syncLocation: false,
|
||||||
|
headerToolbar: [],
|
||||||
|
affixHeader: false,
|
||||||
|
name: 'project_view',
|
||||||
|
footerToolbar: [{ type: 'pagination' }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
size: 'lg',
|
||||||
|
actions: [],
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
},
|
||||||
|
level: 'primary',
|
||||||
|
size: 'xs',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/courses?organization_id=eq.$centre_id&semester_id=eq.$semesterSelect&order=code',
|
||||||
|
data: { page: '$page', perPage: '$perPage' },
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: {\r\n ...payload.data,\r\n items: payload.data.items.map(item => {\r\n return {\r\n ...item,\r\n selected_course_id: item.id\r\n }\r\n })\r\n }\r\n}',
|
||||||
|
},
|
||||||
|
messages: {},
|
||||||
|
syncLocation: false,
|
||||||
|
pageField: 'page',
|
||||||
|
perPageField: 'perPage',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
className: 'p-t-none',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
tabsMode: 'line',
|
||||||
|
tabClassName: '',
|
||||||
|
id: 'u:264fc2e5b77b',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: 'page',
|
||||||
|
messages: {},
|
||||||
|
bodyClassName: '',
|
||||||
|
title: '',
|
||||||
|
definitions: {
|
||||||
|
options: {
|
||||||
|
type: 'combo',
|
||||||
|
multiple: true,
|
||||||
|
multiLine: true,
|
||||||
|
controls: [
|
||||||
|
{
|
||||||
|
type: 'group',
|
||||||
|
controls: [
|
||||||
|
{ label: '选项', name: 'key', type: 'text' },
|
||||||
|
{ label: '内容', name: 'label', type: 'text' },
|
||||||
|
{
|
||||||
|
type: 'switch',
|
||||||
|
option: '开关',
|
||||||
|
name: 'is_fixed',
|
||||||
|
label: '是否固定',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
label: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
id: 'u:21edf657a725',
|
||||||
|
};
|
||||||
|
|
||||||
|
export { schema };
|
||||||
323
src/pages/schema/centre/exam/assessment.schema.ts
Normal file
323
src/pages/schema/centre/exam/assessment.schema.ts
Normal file
@@ -0,0 +1,323 @@
|
|||||||
|
const schema = {
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'crud',
|
||||||
|
name: 'custom_tp',
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/project_process_templates?select=*,exam_paper:exam_paper!project_preparation_exam_exam_paper_id_fk(*)&organization_id=eq.$centre_id&semester_id=eq.${currentSemester}&order=code',
|
||||||
|
adaptor: '',
|
||||||
|
data: { page: '$page', perPage: '$perPage' },
|
||||||
|
requestAdaptor: '',
|
||||||
|
},
|
||||||
|
columns: [
|
||||||
|
{ name: 'code', label: '编号', type: 'text', placeholder: '-' },
|
||||||
|
{ name: 'name', label: '名称', type: 'text', placeholder: '-' },
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '考试试卷',
|
||||||
|
name: 'exam_paper.name',
|
||||||
|
placeholder: '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'tpl',
|
||||||
|
inline: false,
|
||||||
|
name: 'exam_start_fix',
|
||||||
|
label: '上课多久允许答题',
|
||||||
|
style: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '持续时间',
|
||||||
|
placeholder: '-',
|
||||||
|
name: 'exam_duration',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button-group',
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '设置考试',
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '设置实验考试',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'rest/project_preparation_exam',
|
||||||
|
data: {
|
||||||
|
name: '$name',
|
||||||
|
exam_paper_id: '$exam_paper_id',
|
||||||
|
type: '$type',
|
||||||
|
exam_start_time: '$exam_start_time',
|
||||||
|
exam_start_fix: '$exam_start_fix',
|
||||||
|
exam_duration: '$exam_duration',
|
||||||
|
organization_id: '${centre_id}',
|
||||||
|
project_code: '$code',
|
||||||
|
exam_type: 'process_assessment',
|
||||||
|
},
|
||||||
|
requestAdaptor:
|
||||||
|
'if(!api.data.exam_start_fix) {\r\n api.data.exam_start_fix=0;\r\n}\r\nif(!api.data.exam_duration) {\r\n api.data.exam_duration=10;\r\n}\r\nreturn api;',
|
||||||
|
headers: { Prefer: 'resolution=merge-duplicates' },
|
||||||
|
},
|
||||||
|
initApi: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/project_preparation_exam/$template_id',
|
||||||
|
sendOn: 'this.template_id !== null',
|
||||||
|
data: null,
|
||||||
|
adaptor:
|
||||||
|
'if(payload.data.exam_start_time){payload.data.exam_start_time=payload.data.exam_start_time.substring(0,19).replace("T", " ");}\r\nreturn payload;',
|
||||||
|
},
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
label: '名称',
|
||||||
|
name: 'name',
|
||||||
|
mode: 'normal',
|
||||||
|
type: 'input-text',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
label: '选择实验考试试卷',
|
||||||
|
name: 'exam_paper_id',
|
||||||
|
options: [],
|
||||||
|
mode: 'normal',
|
||||||
|
required: true,
|
||||||
|
checkAll: false,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/exam_paper?select=label:name,value:id&type=eq.exam_template_preparation',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'formula',
|
||||||
|
name: 'type',
|
||||||
|
condition: 'data.free_schedule',
|
||||||
|
formula: "'exam_time_fixed'",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'list-select',
|
||||||
|
label: '',
|
||||||
|
name: 'type',
|
||||||
|
mode: 'normal',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: '以上课时间为参考',
|
||||||
|
value: 'exam_time_offset',
|
||||||
|
},
|
||||||
|
{ label: '固定开始时间', value: 'exam_time_fixed' },
|
||||||
|
],
|
||||||
|
value: 'exam_time_offset',
|
||||||
|
disabledOn: 'this.free_schedule',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-datetime',
|
||||||
|
label: '考试时间',
|
||||||
|
name: 'exam_start_time',
|
||||||
|
mode: 'normal',
|
||||||
|
required: true,
|
||||||
|
visibleOn: "this.type === 'exam_time_fixed'",
|
||||||
|
placeholder: '请选择考试日期时间',
|
||||||
|
value: '',
|
||||||
|
minDate: '',
|
||||||
|
maxDate: '',
|
||||||
|
format: 'YYYY-MM-DD HH:mm:ss',
|
||||||
|
inputFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
label: '上课多久允许答题',
|
||||||
|
name: 'exam_start_fix',
|
||||||
|
mode: 'normal',
|
||||||
|
description:
|
||||||
|
'使用d/h/m或D/H/M表示天/小时/分钟,默认为分钟,负值为提前',
|
||||||
|
validations: {
|
||||||
|
matchRegexp1:
|
||||||
|
/^(\d+|\d+[Dd]|\d+[Hh]|\d+[Mm])$|^-(\d+|\d+[Dd]|\d+[Hh]|\d+[Mm])$/,
|
||||||
|
},
|
||||||
|
validationErrors: {
|
||||||
|
matchRegexp1:
|
||||||
|
'请输入正确的格式,使用d/h/m或D/H/M表示天/小时/分钟',
|
||||||
|
},
|
||||||
|
validateOnChange: true,
|
||||||
|
step: 1,
|
||||||
|
required: true,
|
||||||
|
visibleOn: "this.type === 'exam_time_offset'",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
label: '持续时间',
|
||||||
|
name: 'exam_duration',
|
||||||
|
mode: 'normal',
|
||||||
|
description:
|
||||||
|
'使用d/h/m或D/H/M表示天/小时/分钟,默认为分钟',
|
||||||
|
validations: {
|
||||||
|
matchRegexp1: /^(\d+|\d+[Dd]|\d+[Hh]|\d+[Mm])$/,
|
||||||
|
},
|
||||||
|
validationErrors: {
|
||||||
|
matchRegexp1:
|
||||||
|
'请输入正确的格式,使用d/h/m或D/H/M表示天/小时/分钟',
|
||||||
|
},
|
||||||
|
validateOnChange: true,
|
||||||
|
step: 1,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
size: 'lg',
|
||||||
|
closeOnOutside: false,
|
||||||
|
},
|
||||||
|
level: 'primary',
|
||||||
|
icon: 'fa fa-cog',
|
||||||
|
size: 'sm',
|
||||||
|
className: 'pull-right',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
label: '操作',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
messages: {},
|
||||||
|
syncLocation: false,
|
||||||
|
headerToolbar: [],
|
||||||
|
footerToolbar: [
|
||||||
|
{ type: 'pagination' },
|
||||||
|
{ type: 'switch-per-page' },
|
||||||
|
{ type: 'statistics' },
|
||||||
|
],
|
||||||
|
bodyClassName: 'rpt-tp-height',
|
||||||
|
affixHeader: false,
|
||||||
|
perPageAvailable: [10, 20, 30, 40, 50],
|
||||||
|
perPageField: 'perPage',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: 'page',
|
||||||
|
title: '',
|
||||||
|
messages: {},
|
||||||
|
bodyClassName: '',
|
||||||
|
definitions: {
|
||||||
|
variable: {
|
||||||
|
type: 'combo',
|
||||||
|
label: '组合输入',
|
||||||
|
name: 'combo',
|
||||||
|
multiple: true,
|
||||||
|
multiLine: false,
|
||||||
|
joinValues: true,
|
||||||
|
messages: {},
|
||||||
|
mode: 'normal',
|
||||||
|
conditions: [
|
||||||
|
{
|
||||||
|
label: '变量',
|
||||||
|
test: 'this.type === "text"',
|
||||||
|
controls: [{ type: 'text', label: '变量', name: 'string' }],
|
||||||
|
scaffold: { type: 'text', label: '变量', name: '' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '对象',
|
||||||
|
test: 'this.type === "object"',
|
||||||
|
controls: [
|
||||||
|
{ type: 'text', label: '变量', name: 'string' },
|
||||||
|
{ $ref: 'variable' },
|
||||||
|
],
|
||||||
|
scaffold: { type: 'object', label: '对象', name: '' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '数组',
|
||||||
|
test: 'this.type === "array"',
|
||||||
|
controls: [{ $ref: 'variable' }],
|
||||||
|
scaffold: { type: 'array', label: '数组', name: '' },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
textItem: {
|
||||||
|
type: 'group',
|
||||||
|
controls: [
|
||||||
|
{
|
||||||
|
name: 'type',
|
||||||
|
value: 'text',
|
||||||
|
type: 'select',
|
||||||
|
clearable: false,
|
||||||
|
size: 'sm',
|
||||||
|
options: [
|
||||||
|
{ label: '变量', value: 'string' },
|
||||||
|
{ label: '对象', value: 'object' },
|
||||||
|
{ label: '数组', value: 'array' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ name: 'name', type: 'text', placeholder: '名称', required: true },
|
||||||
|
{ name: 'title', type: 'text', placeholder: '说明', required: true },
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
name: 'default',
|
||||||
|
placeholder: '例值',
|
||||||
|
required: true,
|
||||||
|
visibleOn: "this.type==='text'",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
objectItem: {
|
||||||
|
type: 'combo',
|
||||||
|
multiLine: true,
|
||||||
|
controls: [{ name: 'data', value: {}, $ref: 'fieldItem', minLength: 1 }],
|
||||||
|
multiple: false,
|
||||||
|
},
|
||||||
|
arrayItem: {
|
||||||
|
type: 'combo',
|
||||||
|
multiLine: true,
|
||||||
|
controls: [
|
||||||
|
{ name: 'data', value: {}, $ref: 'elementItem', minLength: 1 },
|
||||||
|
],
|
||||||
|
multiple: false,
|
||||||
|
},
|
||||||
|
fieldItem: {
|
||||||
|
type: 'combo',
|
||||||
|
multiple: true,
|
||||||
|
multiLine: true,
|
||||||
|
typeSwitchable: false,
|
||||||
|
controls: [
|
||||||
|
{ $ref: 'textItem', minLength: 0 },
|
||||||
|
{
|
||||||
|
$ref: 'objectItem',
|
||||||
|
minLength: 0,
|
||||||
|
visibleOn: "this.type==='object'",
|
||||||
|
name: 'children',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$ref: 'arrayItem',
|
||||||
|
minLength: 0,
|
||||||
|
visibleOn: "this.type==='array'",
|
||||||
|
name: 'children',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
elementItem: {
|
||||||
|
type: 'combo',
|
||||||
|
multiple: false,
|
||||||
|
multiLine: true,
|
||||||
|
typeSwitchable: false,
|
||||||
|
controls: [
|
||||||
|
{ $ref: 'textItem', minLength: 0, unique: true },
|
||||||
|
{
|
||||||
|
$ref: 'objectItem',
|
||||||
|
minLength: 0,
|
||||||
|
visibleOn: "this.type==='object'",
|
||||||
|
name: 'children',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$ref: 'arrayItem',
|
||||||
|
minLength: 0,
|
||||||
|
visibleOn: "this.type==='array'",
|
||||||
|
name: 'children',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export { schema };
|
||||||
2000
src/pages/schema/centre/exam/index.schema.ts
Normal file
2000
src/pages/schema/centre/exam/index.schema.ts
Normal file
File diff suppressed because it is too large
Load Diff
2944
src/pages/schema/centre/exam/paper.schema.ts
Normal file
2944
src/pages/schema/centre/exam/paper.schema.ts
Normal file
File diff suppressed because it is too large
Load Diff
322
src/pages/schema/centre/exam/preparation.schema.ts
Normal file
322
src/pages/schema/centre/exam/preparation.schema.ts
Normal file
@@ -0,0 +1,322 @@
|
|||||||
|
const schema = {
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'crud',
|
||||||
|
name: 'custom_tp',
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/project_exam_templates?select=*,exam_paper:exam_paper!project_preparation_exam_exam_paper_id_fk(*)&organization_id=eq.$centre_id&semester_id=eq.${currentSemester}&order=code',
|
||||||
|
adaptor: '',
|
||||||
|
data: { page: '$page', perPage: '$perPage' },
|
||||||
|
requestAdaptor: '',
|
||||||
|
},
|
||||||
|
columns: [
|
||||||
|
{ name: 'code', label: '编号', type: 'text', placeholder: '-' },
|
||||||
|
{ name: 'name', label: '名称', type: 'text', placeholder: '-' },
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '考试试卷',
|
||||||
|
name: 'exam_paper.name',
|
||||||
|
placeholder: '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'tpl',
|
||||||
|
inline: false,
|
||||||
|
name: 'exam_start_fix',
|
||||||
|
label: '上课多久允许答题',
|
||||||
|
style: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '持续时间',
|
||||||
|
placeholder: '-',
|
||||||
|
name: 'exam_duration',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button-group',
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '设置考试',
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '设置实验考试',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'rest/project_preparation_exam',
|
||||||
|
data: {
|
||||||
|
name: '$name',
|
||||||
|
exam_paper_id: '$exam_paper_id',
|
||||||
|
type: '$type',
|
||||||
|
exam_start_time: '$exam_start_time',
|
||||||
|
exam_start_fix: '$exam_start_fix',
|
||||||
|
exam_duration: '$exam_duration',
|
||||||
|
organization_id: '${centre_id}',
|
||||||
|
project_code: '$code',
|
||||||
|
},
|
||||||
|
requestAdaptor:
|
||||||
|
'if(!api.data.exam_start_fix) {\r\n api.data.exam_start_fix=0;\r\n}\r\nif(!api.data.exam_duration) {\r\n api.data.exam_duration=10;\r\n}\r\nreturn api;',
|
||||||
|
headers: { Prefer: 'resolution=merge-duplicates' },
|
||||||
|
},
|
||||||
|
initApi: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/project_preparation_exam/$template_id',
|
||||||
|
sendOn: 'this.template_id !== null',
|
||||||
|
data: null,
|
||||||
|
adaptor:
|
||||||
|
'if(payload.data.exam_start_time){payload.data.exam_start_time=payload.data.exam_start_time.substring(0,19).replace("T", " ");}\r\nreturn payload;',
|
||||||
|
},
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
label: '名称',
|
||||||
|
name: 'name',
|
||||||
|
mode: 'normal',
|
||||||
|
type: 'input-text',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
label: '选择实验考试试卷',
|
||||||
|
name: 'exam_paper_id',
|
||||||
|
options: [],
|
||||||
|
mode: 'normal',
|
||||||
|
required: true,
|
||||||
|
checkAll: false,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/exam_paper?select=label:name,value:id&type=eq.exam_template_preparation',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'formula',
|
||||||
|
name: 'type',
|
||||||
|
condition: 'data.free_schedule',
|
||||||
|
formula: "'exam_time_fixed'",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'list-select',
|
||||||
|
label: '',
|
||||||
|
name: 'type',
|
||||||
|
mode: 'normal',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: '以上课时间为参考',
|
||||||
|
value: 'exam_time_offset',
|
||||||
|
},
|
||||||
|
{ label: '固定开始时间', value: 'exam_time_fixed' },
|
||||||
|
],
|
||||||
|
value: 'exam_time_offset',
|
||||||
|
disabledOn: 'this.free_schedule',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-datetime',
|
||||||
|
label: '考试时间',
|
||||||
|
name: 'exam_start_time',
|
||||||
|
mode: 'normal',
|
||||||
|
required: true,
|
||||||
|
visibleOn: "this.type === 'exam_time_fixed'",
|
||||||
|
placeholder: '请选择考试日期时间',
|
||||||
|
value: '',
|
||||||
|
minDate: '',
|
||||||
|
maxDate: '',
|
||||||
|
format: 'YYYY-MM-DD HH:mm:ss',
|
||||||
|
inputFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
label: '上课多久允许答题',
|
||||||
|
name: 'exam_start_fix',
|
||||||
|
mode: 'normal',
|
||||||
|
description:
|
||||||
|
'使用d/h/m或D/H/M表示天/小时/分钟,默认为分钟,负值为提前',
|
||||||
|
validations: {
|
||||||
|
matchRegexp1:
|
||||||
|
/^(\d+|\d+[Dd]|\d+[Hh]|\d+[Mm])$|^-(\d+|\d+[Dd]|\d+[Hh]|\d+[Mm])$/,
|
||||||
|
},
|
||||||
|
validationErrors: {
|
||||||
|
matchRegexp1:
|
||||||
|
'请输入正确的格式,使用d/h/m或D/H/M表示天/小时/分钟',
|
||||||
|
},
|
||||||
|
validateOnChange: true,
|
||||||
|
step: 1,
|
||||||
|
required: true,
|
||||||
|
visibleOn: "this.type === 'exam_time_offset'",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
label: '持续时间',
|
||||||
|
name: 'exam_duration',
|
||||||
|
mode: 'normal',
|
||||||
|
description:
|
||||||
|
'使用d/h/m或D/H/M表示天/小时/分钟,默认为分钟',
|
||||||
|
validations: {
|
||||||
|
matchRegexp1: /^(\d+|\d+[Dd]|\d+[Hh]|\d+[Mm])$/,
|
||||||
|
},
|
||||||
|
validationErrors: {
|
||||||
|
matchRegexp1:
|
||||||
|
'请输入正确的格式,使用d/h/m或D/H/M表示天/小时/分钟',
|
||||||
|
},
|
||||||
|
validateOnChange: true,
|
||||||
|
step: 1,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
size: 'lg',
|
||||||
|
closeOnOutside: false,
|
||||||
|
},
|
||||||
|
level: 'primary',
|
||||||
|
icon: 'fa fa-cog',
|
||||||
|
size: 'sm',
|
||||||
|
className: 'pull-right',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
label: '操作',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
messages: {},
|
||||||
|
syncLocation: false,
|
||||||
|
headerToolbar: [],
|
||||||
|
footerToolbar: [
|
||||||
|
{ type: 'pagination' },
|
||||||
|
{ type: 'switch-per-page' },
|
||||||
|
{ type: 'statistics' },
|
||||||
|
],
|
||||||
|
bodyClassName: 'rpt-tp-height',
|
||||||
|
affixHeader: false,
|
||||||
|
perPageAvailable: [10, 20, 30, 40, 50],
|
||||||
|
perPageField: 'perPage',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: 'page',
|
||||||
|
title: '',
|
||||||
|
messages: {},
|
||||||
|
bodyClassName: '',
|
||||||
|
definitions: {
|
||||||
|
variable: {
|
||||||
|
type: 'combo',
|
||||||
|
label: '组合输入',
|
||||||
|
name: 'combo',
|
||||||
|
multiple: true,
|
||||||
|
multiLine: false,
|
||||||
|
joinValues: true,
|
||||||
|
messages: {},
|
||||||
|
mode: 'normal',
|
||||||
|
conditions: [
|
||||||
|
{
|
||||||
|
label: '变量',
|
||||||
|
test: 'this.type === "text"',
|
||||||
|
controls: [{ type: 'text', label: '变量', name: 'string' }],
|
||||||
|
scaffold: { type: 'text', label: '变量', name: '' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '对象',
|
||||||
|
test: 'this.type === "object"',
|
||||||
|
controls: [
|
||||||
|
{ type: 'text', label: '变量', name: 'string' },
|
||||||
|
{ $ref: 'variable' },
|
||||||
|
],
|
||||||
|
scaffold: { type: 'object', label: '对象', name: '' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '数组',
|
||||||
|
test: 'this.type === "array"',
|
||||||
|
controls: [{ $ref: 'variable' }],
|
||||||
|
scaffold: { type: 'array', label: '数组', name: '' },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
textItem: {
|
||||||
|
type: 'group',
|
||||||
|
controls: [
|
||||||
|
{
|
||||||
|
name: 'type',
|
||||||
|
value: 'text',
|
||||||
|
type: 'select',
|
||||||
|
clearable: false,
|
||||||
|
size: 'sm',
|
||||||
|
options: [
|
||||||
|
{ label: '变量', value: 'string' },
|
||||||
|
{ label: '对象', value: 'object' },
|
||||||
|
{ label: '数组', value: 'array' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ name: 'name', type: 'text', placeholder: '名称', required: true },
|
||||||
|
{ name: 'title', type: 'text', placeholder: '说明', required: true },
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
name: 'default',
|
||||||
|
placeholder: '例值',
|
||||||
|
required: true,
|
||||||
|
visibleOn: "this.type==='text'",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
objectItem: {
|
||||||
|
type: 'combo',
|
||||||
|
multiLine: true,
|
||||||
|
controls: [{ name: 'data', value: {}, $ref: 'fieldItem', minLength: 1 }],
|
||||||
|
multiple: false,
|
||||||
|
},
|
||||||
|
arrayItem: {
|
||||||
|
type: 'combo',
|
||||||
|
multiLine: true,
|
||||||
|
controls: [
|
||||||
|
{ name: 'data', value: {}, $ref: 'elementItem', minLength: 1 },
|
||||||
|
],
|
||||||
|
multiple: false,
|
||||||
|
},
|
||||||
|
fieldItem: {
|
||||||
|
type: 'combo',
|
||||||
|
multiple: true,
|
||||||
|
multiLine: true,
|
||||||
|
typeSwitchable: false,
|
||||||
|
controls: [
|
||||||
|
{ $ref: 'textItem', minLength: 0 },
|
||||||
|
{
|
||||||
|
$ref: 'objectItem',
|
||||||
|
minLength: 0,
|
||||||
|
visibleOn: "this.type==='object'",
|
||||||
|
name: 'children',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$ref: 'arrayItem',
|
||||||
|
minLength: 0,
|
||||||
|
visibleOn: "this.type==='array'",
|
||||||
|
name: 'children',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
elementItem: {
|
||||||
|
type: 'combo',
|
||||||
|
multiple: false,
|
||||||
|
multiLine: true,
|
||||||
|
typeSwitchable: false,
|
||||||
|
controls: [
|
||||||
|
{ $ref: 'textItem', minLength: 0, unique: true },
|
||||||
|
{
|
||||||
|
$ref: 'objectItem',
|
||||||
|
minLength: 0,
|
||||||
|
visibleOn: "this.type==='object'",
|
||||||
|
name: 'children',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$ref: 'arrayItem',
|
||||||
|
minLength: 0,
|
||||||
|
visibleOn: "this.type==='array'",
|
||||||
|
name: 'children',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export { schema };
|
||||||
1642
src/pages/schema/centre/exam/question.schema.ts
Normal file
1642
src/pages/schema/centre/exam/question.schema.ts
Normal file
File diff suppressed because it is too large
Load Diff
1178
src/pages/schema/centre/grade/data.schema.ts
Normal file
1178
src/pages/schema/centre/grade/data.schema.ts
Normal file
File diff suppressed because it is too large
Load Diff
1184
src/pages/schema/centre/grade/operation.schema.ts
Normal file
1184
src/pages/schema/centre/grade/operation.schema.ts
Normal file
File diff suppressed because it is too large
Load Diff
1203
src/pages/schema/centre/grade/overview.schema.ts
Normal file
1203
src/pages/schema/centre/grade/overview.schema.ts
Normal file
File diff suppressed because it is too large
Load Diff
1185
src/pages/schema/centre/grade/preparation.schema.ts
Normal file
1185
src/pages/schema/centre/grade/preparation.schema.ts
Normal file
File diff suppressed because it is too large
Load Diff
1177
src/pages/schema/centre/grade/report.schema.ts
Normal file
1177
src/pages/schema/centre/grade/report.schema.ts
Normal file
File diff suppressed because it is too large
Load Diff
1178
src/pages/schema/centre/grade/studyonline.schema.ts
Normal file
1178
src/pages/schema/centre/grade/studyonline.schema.ts
Normal file
File diff suppressed because it is too large
Load Diff
104
src/pages/schema/centre/mooc/accessory.schema.ts
Normal file
104
src/pages/schema/centre/mooc/accessory.schema.ts
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
const schema = {
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'crud',
|
||||||
|
messages: {},
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/projects?select=*&organization_id=eq.${centre_id}&semester_id=eq.${currentSemester}&order=code',
|
||||||
|
data: { page: '$page', perPage: '$perPage' },
|
||||||
|
},
|
||||||
|
headerToolbar: [],
|
||||||
|
syncLocation: false,
|
||||||
|
pageField: 'page',
|
||||||
|
perPageField: 'perPage',
|
||||||
|
name: 'score',
|
||||||
|
footerToolbar: [
|
||||||
|
{ type: 'pagination' },
|
||||||
|
{ type: 'switch-per-page' },
|
||||||
|
{ type: 'statistics' },
|
||||||
|
],
|
||||||
|
mode: 'table',
|
||||||
|
affixHeader: true,
|
||||||
|
perPageAvailable: [10, 20, 30, 40, 50],
|
||||||
|
columns: [
|
||||||
|
{ name: 'code', type: 'text', label: '编号' },
|
||||||
|
{ type: 'text', name: 'name', label: '名称' },
|
||||||
|
{
|
||||||
|
type: 'operation',
|
||||||
|
label: '操作',
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '附件管理',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
api: {
|
||||||
|
method: 'patch',
|
||||||
|
url: 'rest/projects?id=eq.${id}',
|
||||||
|
data: {
|
||||||
|
files: '${files}',
|
||||||
|
},
|
||||||
|
dataType: 'json',
|
||||||
|
},
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'combo',
|
||||||
|
label: '',
|
||||||
|
name: 'files',
|
||||||
|
mode: 'inline',
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
multiple: true,
|
||||||
|
controls: [
|
||||||
|
{
|
||||||
|
type: 'dataset-picker',
|
||||||
|
bucket: 'mooc',
|
||||||
|
name: 'path',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{ type: 'tpl', tpl: '$path' },
|
||||||
|
],
|
||||||
|
multiLine: false,
|
||||||
|
joinValues: false,
|
||||||
|
draggable: false,
|
||||||
|
strictMode: false,
|
||||||
|
delimiter: ',',
|
||||||
|
scaffold: '',
|
||||||
|
disabled: false,
|
||||||
|
disabledOn: '',
|
||||||
|
removable: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
size: 'lg',
|
||||||
|
},
|
||||||
|
level: 'link',
|
||||||
|
size: 'md',
|
||||||
|
icon: 'fa fa-cog text-warning',
|
||||||
|
tooltip: '附件管理',
|
||||||
|
tooltipPlacement: 'top',
|
||||||
|
iconClassName: 'pull-left',
|
||||||
|
className: 'm-r-none m-l-none',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
placeholder: '-',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
bodyClassName: '',
|
||||||
|
initApi: '',
|
||||||
|
initFetch: '',
|
||||||
|
label: '名称',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: 'page',
|
||||||
|
};
|
||||||
|
|
||||||
|
export { schema };
|
||||||
1042
src/pages/schema/centre/mooc/course.schema.ts
Normal file
1042
src/pages/schema/centre/mooc/course.schema.ts
Normal file
File diff suppressed because it is too large
Load Diff
18
src/pages/schema/centre/mooc/resource.schema.ts
Normal file
18
src/pages/schema/centre/mooc/resource.schema.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
const schema = {
|
||||||
|
type: 'page',
|
||||||
|
body: {
|
||||||
|
type: 'iframe',
|
||||||
|
src: '/res',
|
||||||
|
height: window.innerHeight - 80,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
window.parent.postMessage(
|
||||||
|
{
|
||||||
|
type: 'amis:resize',
|
||||||
|
data: {
|
||||||
|
height: window.innerHeight - 80
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'*'
|
||||||
|
);
|
||||||
|
export { schema };
|
||||||
423
src/pages/schema/centre/notification.schema.ts
Normal file
423
src/pages/schema/centre/notification.schema.ts
Normal file
@@ -0,0 +1,423 @@
|
|||||||
|
const schema = {
|
||||||
|
type: 'page',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'crud',
|
||||||
|
id: 'u:d0a463529569',
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
name: 'title',
|
||||||
|
label: '标题',
|
||||||
|
id: 'u:068708870a6a',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'creator.name',
|
||||||
|
type: 'text',
|
||||||
|
label: '发送人',
|
||||||
|
id: 'u:118fc9ffbf89',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'created_at',
|
||||||
|
label: '发送时间',
|
||||||
|
type: 'date',
|
||||||
|
id: 'u:9f0439c43297',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button-group',
|
||||||
|
label: '操作',
|
||||||
|
id: 'u:537781aa8eec',
|
||||||
|
placeholder: '-',
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
level: 'link',
|
||||||
|
icon: 'fa fa-eye',
|
||||||
|
size: 'md',
|
||||||
|
tooltip: '删除',
|
||||||
|
tooltipPlacement: 'top',
|
||||||
|
iconClassName: 'pull-left',
|
||||||
|
className: 'p-r-none p-l-none',
|
||||||
|
id: 'u:9731651193a3',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '${title}',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'tpl',
|
||||||
|
tpl: '${data}',
|
||||||
|
wrapperComponent: 'p',
|
||||||
|
inline: false,
|
||||||
|
id: 'u:2f15ac0923a7',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
showCloseButton: true,
|
||||||
|
showErrorMsg: true,
|
||||||
|
showLoading: true,
|
||||||
|
className: 'app-popover',
|
||||||
|
id: 'u:93d802668933',
|
||||||
|
closeOnEsc: true,
|
||||||
|
actions: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
confirmText: '确认删除?',
|
||||||
|
level: 'link',
|
||||||
|
icon: 'fa fa-times text-danger',
|
||||||
|
size: 'md',
|
||||||
|
tooltip: '删除',
|
||||||
|
tooltipPlacement: 'top',
|
||||||
|
iconClassName: 'pull-left',
|
||||||
|
className: 'p-r-none p-l-none',
|
||||||
|
id: 'u:9731651193a3',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
outputVar: 'responseResult',
|
||||||
|
actionType: 'ajax',
|
||||||
|
options: {},
|
||||||
|
api: {
|
||||||
|
url: 'rest/notifications/$id',
|
||||||
|
method: 'delete',
|
||||||
|
requestAdaptor: '',
|
||||||
|
adaptor: '',
|
||||||
|
messages: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentId: 'u:d0a463529569',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'reload',
|
||||||
|
args: {
|
||||||
|
resetPage: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
width: 200,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
messages: {},
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/notifications?select=*,creator:users!notification_creator_id_fkey(id,name),user_notifications!user_notification_notification_id_fkey(users(name))&order=created_at.desc&organization_id=eq.${centre_id}&type=eq.announcement',
|
||||||
|
data: null,
|
||||||
|
},
|
||||||
|
headerToolbar: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
align: 'right',
|
||||||
|
icon: 'fa fa-plus text-primary',
|
||||||
|
level: 'link',
|
||||||
|
label: '',
|
||||||
|
id: 'u:6adf561275c3',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '发送消息',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'rest/notifications',
|
||||||
|
data: {
|
||||||
|
'&': '$$',
|
||||||
|
organization_id: '$centre_id',
|
||||||
|
},
|
||||||
|
dataType: 'json',
|
||||||
|
requestAdaptor:
|
||||||
|
"let notification = {\r\n title: api.data.title,\r\n data: api.data.data,\r\n push2wechat: api.data.push2wechat,\r\n organization_id: api.data.organization_id\r\n};\r\nconsole.log(api)\r\nif (!api.data.push2wechat && api.data.target === 'toorg') {\r\n notification.org_list = `{${api.data.org_list}}`\r\n} else if (!api.data.push2wechat && api.data.target === 'touser') {\r\n notification.user_id_list = `{${api.data.user_id_list}}`\r\n}\r\nreturn {\r\n ...api,\r\n data: notification\r\n}",
|
||||||
|
},
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'group',
|
||||||
|
label: false,
|
||||||
|
name: 'title',
|
||||||
|
id: 'u:5cb966ef8b55',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
label: '',
|
||||||
|
name: 'title',
|
||||||
|
mode: 'normal',
|
||||||
|
required: true,
|
||||||
|
columnRatio: 9,
|
||||||
|
placeholder: '消息标题',
|
||||||
|
id: 'u:2e6661386694',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'switch',
|
||||||
|
name: 'push2wechat',
|
||||||
|
option: '是否推送微信消息',
|
||||||
|
mode: 'normal',
|
||||||
|
label: '',
|
||||||
|
optionAtLeft: false,
|
||||||
|
trueValue: true,
|
||||||
|
falseValue: false,
|
||||||
|
value: false,
|
||||||
|
id: 'u:90d1abf14f6c',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'control',
|
||||||
|
label: '发送给谁',
|
||||||
|
mode: 'normal',
|
||||||
|
id: 'u:9064f08b91d6',
|
||||||
|
className: 'm-t-sm',
|
||||||
|
visibleOn: '!this.push2wechat',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'grid',
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
label: '',
|
||||||
|
name: 'target',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: '所有人',
|
||||||
|
value: 'toall',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '指定班级',
|
||||||
|
value: 'toorg',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '指定人',
|
||||||
|
value: 'touser',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
checkAll: false,
|
||||||
|
required: true,
|
||||||
|
value: 'touser',
|
||||||
|
visibleOn: '',
|
||||||
|
className: '1css',
|
||||||
|
labelClassName: '2css',
|
||||||
|
inputClassName: '3css',
|
||||||
|
id: 'u:150a4240cd56',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:65ffd686a587',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
label: '',
|
||||||
|
name: 'org_list',
|
||||||
|
type: 'picker',
|
||||||
|
visibleOn: "this.target === 'toorg'",
|
||||||
|
required: true,
|
||||||
|
pickerSchema: {
|
||||||
|
mode: 'list',
|
||||||
|
listItem: {
|
||||||
|
title: '${label}',
|
||||||
|
},
|
||||||
|
messages: {},
|
||||||
|
syncLocation: false,
|
||||||
|
defaultParams: {
|
||||||
|
page: 1,
|
||||||
|
perPage: 10,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/orgs?type=eq.class',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: {\r\n ...payload.data,\r\n items: payload.data.items.map(item => {\r\n return {\r\n label: item.name,\r\n value: item.id\r\n }\r\n })\r\n }\r\n}',
|
||||||
|
},
|
||||||
|
multiple: true,
|
||||||
|
mode: 'normal',
|
||||||
|
modalMode: 'dialog',
|
||||||
|
joinValues: true,
|
||||||
|
id: 'u:8cb5375b4bfb',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'picker',
|
||||||
|
name: 'user_id_list',
|
||||||
|
visibleOn: "this.target === 'touser'",
|
||||||
|
required: true,
|
||||||
|
pickerSchema: {
|
||||||
|
mode: 'list',
|
||||||
|
listItem: {
|
||||||
|
title: '${label}',
|
||||||
|
},
|
||||||
|
messages: {},
|
||||||
|
footerToolbar: [
|
||||||
|
{
|
||||||
|
type: 'pagination',
|
||||||
|
tpl: '内容',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
defaultParams: {
|
||||||
|
perPage: 10,
|
||||||
|
page: 1,
|
||||||
|
},
|
||||||
|
syncLocation: false,
|
||||||
|
filter: {
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
wrapWithPanel: false,
|
||||||
|
submitOnInit: false,
|
||||||
|
submitOnChange: false,
|
||||||
|
target: '',
|
||||||
|
resetAfterSubmit: false,
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
name: 'keywords',
|
||||||
|
clearable: true,
|
||||||
|
size: 'md',
|
||||||
|
label: '学号',
|
||||||
|
id: 'u:8a6776c917cd',
|
||||||
|
mode: 'inline',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'control',
|
||||||
|
id: 'u:fa7b6a89a71b',
|
||||||
|
label: '',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
level: 'primary',
|
||||||
|
actionType: 'submit',
|
||||||
|
label: '搜索',
|
||||||
|
id: 'u:544f3de716b9',
|
||||||
|
reload:
|
||||||
|
'userlist?code=like.*${keywords}*',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
mode: 'inline',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:e95d6e701a18',
|
||||||
|
},
|
||||||
|
name: 'userlist',
|
||||||
|
},
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/users?role=eq.student&order=code',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: {\r\n ...payload.data,\r\n items: payload.data.items.map(item => {\r\n return {\r\n label: `${item.code}-${item.name}`,\r\n value: item.id\r\n }\r\n })\r\n }\r\n}',
|
||||||
|
data: {
|
||||||
|
'&': '$$',
|
||||||
|
keywords: '__undefined',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
modalMode: 'dialog',
|
||||||
|
multiple: true,
|
||||||
|
joinValues: false,
|
||||||
|
mode: 'normal',
|
||||||
|
label: '',
|
||||||
|
extractValue: true,
|
||||||
|
id: 'u:eff885fa85ae',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:5352be84ebdb',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
className: '',
|
||||||
|
id: 'u:7a1bff6ac12a',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-rich-text',
|
||||||
|
label: '内容',
|
||||||
|
name: 'data',
|
||||||
|
mode: 'normal',
|
||||||
|
required: true,
|
||||||
|
inputClassName: 'm-t-sm',
|
||||||
|
options: {
|
||||||
|
menubar: false,
|
||||||
|
},
|
||||||
|
id: 'u:1ff80f85808d',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:b2bb8e58c569',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'submit',
|
||||||
|
label: '提交',
|
||||||
|
primary: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
feat: 'Insert',
|
||||||
|
dsType: 'api',
|
||||||
|
onEvent: {
|
||||||
|
submitSucc: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
componentId: 'u:d0a463529569',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'reload',
|
||||||
|
args: {
|
||||||
|
resetPage: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
size: 'md',
|
||||||
|
id: 'u:50bb302aecfa',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'cancel',
|
||||||
|
label: '取消',
|
||||||
|
id: 'u:2a8cd9b988ff',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'confirm',
|
||||||
|
label: '确定',
|
||||||
|
primary: true,
|
||||||
|
id: 'u:2e2b83a9fcd0',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
size: 'lg',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:cd729a982c31',
|
||||||
|
};
|
||||||
|
|
||||||
|
export { schema };
|
||||||
3665
src/pages/schema/centre/plan/course.schema.ts
Normal file
3665
src/pages/schema/centre/plan/course.schema.ts
Normal file
File diff suppressed because it is too large
Load Diff
929
src/pages/schema/centre/plan/group.schema.ts
Normal file
929
src/pages/schema/centre/plan/group.schema.ts
Normal file
@@ -0,0 +1,929 @@
|
|||||||
|
const schema = {
|
||||||
|
type: 'page',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
id: 'u:90c6fa536042',
|
||||||
|
mode: 'inline',
|
||||||
|
name: 'filter',
|
||||||
|
title: '表单',
|
||||||
|
className: 'm-b-sm',
|
||||||
|
submitOnChange: true,
|
||||||
|
submitOnInit: true,
|
||||||
|
reload:
|
||||||
|
'group?course_id=$course_id&class_ids=$class_ids&studentgroup_ids=$studentgroup_ids',
|
||||||
|
wrapWithPanel: false,
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'group',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
mode: 'inline',
|
||||||
|
label: '课程',
|
||||||
|
name: 'course_id',
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/courses?organization_id=eq.$centre_id&semester_id=eq.$currentSemester&order=code',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: payload.data.items.map(item => {\r\n return {\r\n label: `${item.name}(${item.code})`,\r\n value: item.id\r\n }\r\n })\r\n}',
|
||||||
|
},
|
||||||
|
size: 'md',
|
||||||
|
searchable: true,
|
||||||
|
className: 'm-l-sm',
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
id: 'u:23277f1965f7',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:8575c6f7cefc',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'group',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'tree-select',
|
||||||
|
label: '班级',
|
||||||
|
name: 'class_ids',
|
||||||
|
mode: 'horizontal',
|
||||||
|
multiple: true,
|
||||||
|
joinValues: false,
|
||||||
|
extractValue: true,
|
||||||
|
onlyChildren: true,
|
||||||
|
clearable: true,
|
||||||
|
searchable: true,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/orgs?select=*,dicts:dicts!organization_type_fkey(*),course2orgs(*)&path=cd.root&course2orgs.course_id=eq.${course_id}&order=name',
|
||||||
|
adaptor:
|
||||||
|
"const recursive = id => {\r\n const nodes = payload.data.items.filter(item => {\r\n return item.parent === id && (\r\n (item.type === 'class' ||\r\n item.type === 'reelectclass') &&\r\n item.course2orgs.length ||\r\n item.type !== 'class' &&\r\n item.type !== 'reelectclass' &&\r\n item.type !== 'studentgroup'\r\n )\r\n })\r\n const result = []\r\n\r\n if (nodes.length) {\r\n nodes.forEach(item => {\r\n const children = recursive(item.id)\r\n\r\n if (children)\r\n result.push({\r\n ...item,\r\n label: item.name,\r\n children,\r\n })\r\n else if (\r\n item.type === 'class' ||\r\n item.type === 'reelectclass'\r\n ) result.push({\r\n ...item,\r\n label: item.name,\r\n value: item.id,\r\n })\r\n })\r\n\r\n if (result.length) return result\r\n } else return null\r\n}\r\n\r\nlet school = payload.data.items.find(x => x.type === 'school')\r\n\r\nreturn {\r\n ...payload,\r\n data: recursive(school.id)\r\n}\r\n",
|
||||||
|
requestAdaptor:
|
||||||
|
'if (api.query.course2orgs.course_id === "eq.") {\r\n \n api.url = api.url.replace("&course2orgs[course_id]=eq.", "")\r\n}\r\nif (api.query.course2orgs.course_id === "eq.undefined") {\r\n api.url = api.url.replace("&course2orgs[course_id]=eq.undefined", "")\r\n}',
|
||||||
|
sendOn: 'course_id',
|
||||||
|
messages: {},
|
||||||
|
},
|
||||||
|
withChildren: true,
|
||||||
|
initiallyOpen: false,
|
||||||
|
id: 'u:42ede681efa8',
|
||||||
|
autoCheckChildren: true,
|
||||||
|
enableNodePath: false,
|
||||||
|
showIcon: true,
|
||||||
|
heightAuto: true,
|
||||||
|
virtualThreshold: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:f2885926e84d',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'group',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'tree-select',
|
||||||
|
label: '分组',
|
||||||
|
name: 'studentgroup_ids',
|
||||||
|
mode: 'horizontal',
|
||||||
|
multiple: true,
|
||||||
|
joinValues: false,
|
||||||
|
extractValue: true,
|
||||||
|
onlyChildren: true,
|
||||||
|
clearable: true,
|
||||||
|
searchable: true,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/orgs?select=*,dicts:dicts!organization_type_fkey(*),course2orgs(*)&path=cd.root&course2orgs.course_id=eq.${course_id}&order=name',
|
||||||
|
adaptor:
|
||||||
|
"const recursive = id => {\r\n const nodes = payload.data.items.filter(item => {\r\n return item.parent === id && (\r\n item.type === 'studentgroup' &&\r\n item.course2orgs.length ||\r\n item.type !== 'class' &&\r\n item.type !== 'reelectclass' &&\r\n item.type !== 'studentgroup'\r\n )\r\n })\r\n const result = []\r\n\r\n if (nodes.length) {\r\n nodes.forEach(item => {\r\n const children = recursive(item.id)\r\n\r\n if (children)\r\n result.push({\r\n ...item,\r\n label: item.name,\r\n children,\r\n })\r\n else if (item.type === 'studentgroup')\r\n result.push({\r\n ...item,\r\n label: item.name,\r\n value: item.id,\r\n })\r\n })\r\n\r\n if (result.length) return result\r\n } else return null\r\n}\r\n\r\nlet school = payload.data.items.find(x => x.type === 'school')\r\n\r\nreturn {\r\n ...payload,\r\n data: recursive(school.id)\r\n}\r\n",
|
||||||
|
requestAdaptor:
|
||||||
|
'if (api.query.course2orgs.course_id === "eq.") {\r\n \n api.url = api.url.replace("&course2orgs[course_id]=eq.", "")\r\n}\r\nif (api.query.course2orgs.course_id === "eq.undefined") {\r\n api.url = api.url.replace("&course2orgs[course_id]=eq.undefined", "")\r\n}',
|
||||||
|
sendOn: 'course_id',
|
||||||
|
messages: {},
|
||||||
|
},
|
||||||
|
withChildren: true,
|
||||||
|
initiallyOpen: false,
|
||||||
|
id: 'u:42ede681efa8',
|
||||||
|
autoCheckChildren: true,
|
||||||
|
enableNodePath: false,
|
||||||
|
showIcon: true,
|
||||||
|
heightAuto: true,
|
||||||
|
virtualThreshold: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:bfa2b4c7ed01',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
feat: 'Insert',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'divider',
|
||||||
|
lineStyle: 'solid',
|
||||||
|
id: 'u:e807ff502b0a',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'crud',
|
||||||
|
messages: {},
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/groupusers?semester_id=eq.$currentSemester&course_id=eq.$course_id&or=(class_id.in.($class_ids),studentgroup_id.in.($studentgroup_ids))&order=student_code',
|
||||||
|
sendOn: 'this.course_id && (this.class_ids || this.studentgroup_ids)',
|
||||||
|
data: {
|
||||||
|
orderBy: '$orderBy',
|
||||||
|
orderDir: '$orderDir',
|
||||||
|
},
|
||||||
|
requestAdaptor:
|
||||||
|
"if (api.query.orderDir) {\r\n api.url = api.url.replace('&order=student_code', '');\r\n api.url = api.url.replace('&orderBy=' + api.query.orderBy + '&orderDir=' + api.query.orderDir, '&order=' + api.query.orderBy + '.' + api.query.orderDir);\r\n} else if (api.query.orderBy) {\r\n api.url = api.url.replace('&order=student_code', '');\r\n api.url = api.url.replace('&orderBy=' + api.query.orderBy + '&orderDir=', '&order=' + api.query.orderBy);\r\n} else {\r\n api.url = api.url.replace('&orderBy=&orderDir=', '');\r\n}\r\n\r\nreturn api;",
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: {\r\n ...payload.data,\r\n items: payload.data.items.map((item, index) => {\r\n return {\r\n ...item,\r\n n: index + 1\r\n }\r\n })\r\n }\r\n}',
|
||||||
|
},
|
||||||
|
headerToolbar: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
align: 'right',
|
||||||
|
label: '导入分组',
|
||||||
|
icon: 'fa fa-upload',
|
||||||
|
level: 'warning',
|
||||||
|
id: 'u:ce034375ceff',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '分组导入',
|
||||||
|
size: 'xl',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
mode: 'inline',
|
||||||
|
label: '课程',
|
||||||
|
name: 'course_id',
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/courses?organization_id=eq.$centre_id&semester_id=eq.$currentSemester&order=code',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: payload.data.items.map(item => {\r\n return {\r\n label: `${item.name}(${item.code})`,\r\n value: item.id\r\n }\r\n })\r\n}',
|
||||||
|
},
|
||||||
|
size: 'md',
|
||||||
|
searchable: true,
|
||||||
|
className: 'm-l-sm',
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
id: 'u:7cfa89be2243',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'tree-select',
|
||||||
|
label: '上级部门',
|
||||||
|
name: 'parent_id',
|
||||||
|
mode: 'inline',
|
||||||
|
extractValue: true,
|
||||||
|
onlyChildren: true,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/orgs?select=*&or=(type.eq.school,type.eq.faculty,type.eq.centre)&path=cd.root&order=code',
|
||||||
|
adaptor:
|
||||||
|
"const recursive = id => {\r\n let nodes = payload.data.items.filter(x => {\r\n return x.parent === id\r\n })\r\n\r\n return nodes.map(item => {\r\n return {\r\n ...item,\r\n label: item.name,\r\n value: `${item.id}`,\r\n children: recursive(item.id)\r\n }\r\n })\r\n}\r\n\r\nlet school = payload.data.items.find(x => x.type === 'school')\r\n\r\nreturn {\r\n ...payload,\r\n data: recursive(school.id)\r\n}\r\n",
|
||||||
|
sendOn: '',
|
||||||
|
},
|
||||||
|
withChildren: true,
|
||||||
|
initiallyOpen: false,
|
||||||
|
searchable: true,
|
||||||
|
clearable: false,
|
||||||
|
heightAuto: true,
|
||||||
|
virtualThreshold: false,
|
||||||
|
id: 'u:37ca2401871c',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'excel-import-group',
|
||||||
|
name: 'groups',
|
||||||
|
label: '',
|
||||||
|
mode: 'normal',
|
||||||
|
hiddenOn: '${!course_id || !parent_id}',
|
||||||
|
id: 'u:a8c9dbf3d073',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-table',
|
||||||
|
name: 'groups',
|
||||||
|
label: '',
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
label: 'Excel 行号',
|
||||||
|
name: 'no',
|
||||||
|
id: 'u:a31efd3393b0',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'user_code',
|
||||||
|
label: '*学号',
|
||||||
|
classNameExpr:
|
||||||
|
"<%= data.no && !data.user_id ? 'bg-danger' : '' %>",
|
||||||
|
id: 'u:8d68435bf70e',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '姓名',
|
||||||
|
name: 'user_name',
|
||||||
|
id: 'u:fc9cb5a03b8f',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '分组',
|
||||||
|
name: 'group',
|
||||||
|
classNameExpr:
|
||||||
|
"<%= !data.no ? 'bg-secondary' : !data.group ? 'bg-danger' : '' %>",
|
||||||
|
id: 'u:ca487d89fd7c',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
mode: 'normal',
|
||||||
|
visibleOn: 'this.groups',
|
||||||
|
strictMode: true,
|
||||||
|
removable: true,
|
||||||
|
editable: false,
|
||||||
|
clearValueOnHidden: true,
|
||||||
|
id: 'u:625db3dac0ec',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
reload: 'grp',
|
||||||
|
initApi: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/report_check_items?organization_id=eq.$centre_id&order=type_order,type,display_order,comment',
|
||||||
|
},
|
||||||
|
id: 'u:ccd0d1410b18',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'submit',
|
||||||
|
label: '提交',
|
||||||
|
primary: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
feat: 'View',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closeOnEsc: true,
|
||||||
|
closeOnOutside: false,
|
||||||
|
showCloseButton: true,
|
||||||
|
actions: [],
|
||||||
|
id: 'u:d85ab95adb25',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'export-excel',
|
||||||
|
align: 'right',
|
||||||
|
label: '导出',
|
||||||
|
icon: 'fa fa-download',
|
||||||
|
level: 'primary',
|
||||||
|
hiddenOn: '${!class_ids && !studentgroup_ids}',
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/groupusers?semester_id=eq.$currentSemester&course_id=eq.$course_id&or=(class_id.in.($class_ids),studentgroup_id.in.($studentgroup_ids))&order=student_code',
|
||||||
|
data: {
|
||||||
|
orderBy: '$orderBy',
|
||||||
|
orderDir: '$orderDir',
|
||||||
|
},
|
||||||
|
requestAdaptor:
|
||||||
|
"if (api.query.orderDir) {\r\n api.url = api.url.replace('&order=student_code', '');\r\n api.url = api.url.replace('&orderBy=' + api.query.orderBy + '&orderDir=' + api.query.orderDir, '&order=' + api.query.orderBy + '.' + api.query.orderDir);\r\n} else if (api.query.orderBy) {\r\n api.url = api.url.replace('&order=student_code', '');\r\n api.url = api.url.replace('&orderBy=' + api.query.orderBy + '&orderDir=', '&order=' + api.query.orderBy);\r\n} else {\r\n api.url = api.url.replace('&orderBy=&orderDir=', '');\r\n}\r\n\r\nreturn api;",
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: {\r\n ...payload.data,\r\n items: payload.data.items.map((item, index) => {\r\n return {\r\n ...item,\r\n n: index + 1\r\n }\r\n })\r\n }\r\n}',
|
||||||
|
},
|
||||||
|
filename: '分组',
|
||||||
|
exportColumns: [
|
||||||
|
{
|
||||||
|
label: '*学号',
|
||||||
|
name: 'student_code',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '姓名',
|
||||||
|
name: 'student_name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '*分组',
|
||||||
|
name: 'studentgroup_name',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:a44ab3164746',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'bulk-actions',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
bulkActions: [
|
||||||
|
{
|
||||||
|
label: '批量设置',
|
||||||
|
type: 'button',
|
||||||
|
id: 'u:99fa372537dc',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '批量设置',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'rest/rpc/batch_group',
|
||||||
|
data: {
|
||||||
|
org_id: '$org_id',
|
||||||
|
selectedItems: '$selectedItems',
|
||||||
|
},
|
||||||
|
heades: {
|
||||||
|
Prefer: 'params=single-object',
|
||||||
|
},
|
||||||
|
requestAdaptor:
|
||||||
|
'const user2org = api.data.selectedItems.map(item => ({\r\n user_id: item.student_id,\r\n old_org_id: item.studentgroup_id,\r\n new_org_id: api.data.org_id,\r\n}))\r\n\r\napi.data = { user2org }\r\n\r\nreturn api',
|
||||||
|
},
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
label: '分组',
|
||||||
|
name: 'org_id',
|
||||||
|
mode: 'normal',
|
||||||
|
cascade: true,
|
||||||
|
searchable: true,
|
||||||
|
required: true,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/orgs?select=*,course2orgs!inner(*),dicts:dicts!organization_type_fkey(*)&type=eq.studentgroup&path=cd.root.1&course2orgs.course_id=eq.${course_id}&order=name',
|
||||||
|
requestAdaptor:
|
||||||
|
'if (api.query.course2orgs.course_id === "eq.") {\r\n api.url = api.url.replace("&course2orgs[course_id]=eq.", "")\r\n}\r\nif (api.query.course2orgs.course_id === "eq.undefined") {\r\n api.url = api.url.replace("&course2orgs[course_id]=eq.undefined", "")\r\n}',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n data: payload.data.items.map(item => {\r\n return {\r\n label: item.name,\r\n value: item.id\r\n }\r\n })\r\n}',
|
||||||
|
sendOn: 'course_id',
|
||||||
|
},
|
||||||
|
extractValue: true,
|
||||||
|
id: 'u:8527f8d399e6',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:e9215f23110f',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'submit',
|
||||||
|
label: '提交',
|
||||||
|
primary: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
feat: 'Insert',
|
||||||
|
dsType: 'api',
|
||||||
|
onEvent: {
|
||||||
|
submitSucc: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
componentId: 'u:148f700a4963',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'reload',
|
||||||
|
args: {
|
||||||
|
resetPage: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
id: 'u:ce48989de1f9',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'cancel',
|
||||||
|
label: '取消',
|
||||||
|
id: 'u:f8c9f57fa665',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'confirm',
|
||||||
|
label: '确定',
|
||||||
|
primary: true,
|
||||||
|
id: 'u:8cccdee1e21b',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '批量清除',
|
||||||
|
confirmText: '确认清除分组吗?',
|
||||||
|
type: 'button',
|
||||||
|
id: 'u:5eb51d3e6692',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
outputVar: 'responseResult',
|
||||||
|
actionType: 'ajax',
|
||||||
|
options: {},
|
||||||
|
api: {
|
||||||
|
url: 'rest/user_orgs',
|
||||||
|
method: 'delete',
|
||||||
|
requestAdaptor:
|
||||||
|
'api.url = api.url + `?id=in.(${api.data.selectedItems.filter(item => item.user_studentgroup_id).map(item => item.user_studentgroup_id).toString()})`\r\ndelete api.data.selectedItems\r\n\r\nreturn api',
|
||||||
|
adaptor: '',
|
||||||
|
messages: {},
|
||||||
|
data: {
|
||||||
|
selectedItems: '$selectedItems',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentId: 'u:148f700a4963',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'reload',
|
||||||
|
args: {
|
||||||
|
resetPage: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '批量分组',
|
||||||
|
type: 'button',
|
||||||
|
id: 'u:0371266b981c',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '批量分组',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
id: 'u:f39e60c373bc',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'tree-select',
|
||||||
|
label: '上级部门',
|
||||||
|
name: 'parent',
|
||||||
|
mode: 'normal',
|
||||||
|
extractValue: true,
|
||||||
|
onlyChildren: true,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/orgs?select=*&or=(type.eq.school,type.eq.faculty,type.eq.centre)&path=cd.root&order=code',
|
||||||
|
adaptor:
|
||||||
|
"const recursive = id => {\r\n let nodes = payload.data.items.filter(x => {\r\n return x.parent === id\r\n })\r\n\r\n return nodes.map(item => {\r\n return {\r\n ...item,\r\n label: item.name,\r\n value: `${item.id}`,\r\n children: recursive(item.id)\r\n }\r\n })\r\n}\r\n\r\nlet school = payload.data.items.find(x => x.type === 'school')\r\n\r\nreturn {\r\n ...payload,\r\n data: recursive(school.id)\r\n}\r\n",
|
||||||
|
sendOn: '',
|
||||||
|
},
|
||||||
|
withChildren: true,
|
||||||
|
required: true,
|
||||||
|
initiallyOpen: false,
|
||||||
|
searchable: true,
|
||||||
|
clearable: false,
|
||||||
|
heightAuto: true,
|
||||||
|
virtualThreshold: false,
|
||||||
|
id: 'u:1efc22d916f7',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'groups',
|
||||||
|
label: '新分组',
|
||||||
|
type: 'input-array',
|
||||||
|
items: {
|
||||||
|
type: 'input-text',
|
||||||
|
},
|
||||||
|
removable: true,
|
||||||
|
required: true,
|
||||||
|
mode: 'normal',
|
||||||
|
id: 'u:0a41abbda787',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '选择分组方式',
|
||||||
|
type: 'select',
|
||||||
|
name: 'way',
|
||||||
|
required: true,
|
||||||
|
mode: 'normal',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: '顺序分组',
|
||||||
|
value: 'order',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '随机分组',
|
||||||
|
value: 'random',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:436b4893fdfc',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'batch-group',
|
||||||
|
label: false,
|
||||||
|
id: 'u:04fbf3b1b31c',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'submit',
|
||||||
|
label: '提交',
|
||||||
|
primary: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
feat: 'Insert',
|
||||||
|
dsType: 'api',
|
||||||
|
onEvent: {
|
||||||
|
submitSucc: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
componentId: 'u:148f700a4963',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'reload',
|
||||||
|
args: {
|
||||||
|
resetPage: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '关闭',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
componentId: 'u:148f700a4963',
|
||||||
|
actionType: 'reload',
|
||||||
|
data: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
actionType: 'closeDialog',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
id: 'u:f7831022039a',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:3ead95907fbd',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
syncLocation: false,
|
||||||
|
footerToolbar: [],
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
name: 'n',
|
||||||
|
label: '序号',
|
||||||
|
id: 'u:dc3b48ab2a2a',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
name: 'student_code',
|
||||||
|
sortable: true,
|
||||||
|
label: '学号',
|
||||||
|
id: 'u:9233f140d314',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
name: 'student_name',
|
||||||
|
sortable: true,
|
||||||
|
label: '姓名',
|
||||||
|
id: 'u:cb913014ed05',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
sortable: true,
|
||||||
|
label: '班级',
|
||||||
|
name: 'class_name',
|
||||||
|
id: 'u:d0de67b68472',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '课程',
|
||||||
|
name: 'course_name',
|
||||||
|
id: 'u:ecd0d94b6c58',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
sortable: true,
|
||||||
|
label: '分组',
|
||||||
|
name: 'studentgroup_name',
|
||||||
|
id: 'u:de1610df96e6',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button-group',
|
||||||
|
label: '操作',
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
level: 'link',
|
||||||
|
icon: 'fa fa-cog text-info',
|
||||||
|
size: 'md',
|
||||||
|
tooltip: '设置分组',
|
||||||
|
tooltipPlacement: 'top',
|
||||||
|
iconClassName: 'pull-left',
|
||||||
|
className: 'p-r-none p-l-none',
|
||||||
|
hiddenOn: '${studentgroup_id}',
|
||||||
|
id: 'u:ccec6786dabf',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
title: '设置分组',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'rest/user_orgs',
|
||||||
|
data: {
|
||||||
|
user_id: '$student_id',
|
||||||
|
organization_id: '$group_id',
|
||||||
|
},
|
||||||
|
dataType: 'json',
|
||||||
|
},
|
||||||
|
id: 'u:a20070f8b13c',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
label: '分组',
|
||||||
|
name: 'group_id',
|
||||||
|
mode: 'normal',
|
||||||
|
cascade: true,
|
||||||
|
searchable: true,
|
||||||
|
required: true,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/orgs?select=*,course2orgs!inner(*),dicts:dicts!organization_type_fkey(*)&type=eq.studentgroup&path=cd.root.1&course2orgs.course_id=eq.${course_id}&order=name',
|
||||||
|
requestAdaptor:
|
||||||
|
'if (api.query.course2orgs.course_id === "eq.") {\r\n api.url = api.url.replace("&course2orgs[course_id]=eq.", "")\r\n}\r\nif (api.query.course2orgs.course_id === "eq.undefined") {\r\n api.url = api.url.replace("&course2orgs[course_id]=eq.undefined", "")\r\n}',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n data: payload.data.items.map(item => {\r\n return {\r\n label: item.name,\r\n value: item.id\r\n }\r\n })\r\n}',
|
||||||
|
sendOn: 'course_id',
|
||||||
|
},
|
||||||
|
extractValue: true,
|
||||||
|
id: 'u:75a5e1ef2a35',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'submit',
|
||||||
|
label: '提交',
|
||||||
|
primary: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
feat: 'Insert',
|
||||||
|
dsType: 'api',
|
||||||
|
onEvent: {
|
||||||
|
submitSucc: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
componentId: 'u:148f700a4963',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'reload',
|
||||||
|
args: {
|
||||||
|
resetPage: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: 'dialog',
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
id: 'u:05921ba2d106',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'cancel',
|
||||||
|
label: '取消',
|
||||||
|
id: 'u:5a3bed9137d5',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'confirm',
|
||||||
|
label: '确定',
|
||||||
|
primary: true,
|
||||||
|
id: 'u:9982eb0126f2',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
level: 'link',
|
||||||
|
icon: 'fa fa-pencil text-warning',
|
||||||
|
size: 'md',
|
||||||
|
tooltip: '修改分组',
|
||||||
|
tooltipPlacement: 'top',
|
||||||
|
hiddenOn: '${!studentgroup_id}',
|
||||||
|
iconClassName: 'pull-left',
|
||||||
|
className: 'p-r-none p-l-none',
|
||||||
|
id: 'u:b1bda5ad847a',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
title: '修改分组',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
api: {
|
||||||
|
method: 'patch',
|
||||||
|
url: 'rest/user_orgs?user_id=eq.$student_id&organization_id=eq.$studentgroup_id',
|
||||||
|
data: {
|
||||||
|
organization_id: '$group_id',
|
||||||
|
},
|
||||||
|
dataType: 'json',
|
||||||
|
},
|
||||||
|
id: 'u:2b0b7a8f5877',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'tree-select',
|
||||||
|
label: '原分组',
|
||||||
|
name: 'studentgroup_id',
|
||||||
|
searchable: true,
|
||||||
|
readOnly: true,
|
||||||
|
onlyChildren: true,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/orgs?select=*&or=(type.eq.school,type.eq.faculty,type.eq.centre,type.eq.studentgroup)&path=cd.root&order=code',
|
||||||
|
adaptor:
|
||||||
|
"const recursive = id => {\r\n let nodes = payload.data.items.filter(x => {\r\n return x.parent === id\r\n })\r\n\r\n return nodes.map(item => {\r\n return {\r\n ...item,\r\n label: item.name,\r\n value: item.id,\r\n children: recursive(item.id)\r\n }\r\n })\r\n}\r\n\r\nlet school = payload.data.items.find(x => x.type === 'school')\r\n\r\nreturn {\r\n ...payload,\r\n data: recursive(school.id)\r\n}\r\n",
|
||||||
|
},
|
||||||
|
withChildren: true,
|
||||||
|
initiallyOpen: false,
|
||||||
|
heightAuto: true,
|
||||||
|
virtualThreshold: false,
|
||||||
|
id: 'u:9b803b7fffbe',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
label: '新分组',
|
||||||
|
name: 'group_id',
|
||||||
|
mode: 'normal',
|
||||||
|
cascade: true,
|
||||||
|
searchable: true,
|
||||||
|
required: true,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/orgs?select=*,course2orgs!inner(*),dicts:dicts!organization_type_fkey(*)&type=eq.studentgroup&path=cd.root.1&course2orgs.course_id=eq.${course_id}&order=name',
|
||||||
|
requestAdaptor:
|
||||||
|
'if (api.query.course2orgs.course_id === "eq.") {\r\n api.url = api.url.replace("&course2orgs[course_id]=eq.", "")\r\n}\r\nif (api.query.course2orgs.course_id === "eq.undefined") {\r\n api.url = api.url.replace("&course2orgs[course_id]=eq.undefined", "")\r\n}',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n data: payload.data.items.map(item => {\r\n return {\r\n label: item.name,\r\n value: item.id\r\n }\r\n })\r\n}',
|
||||||
|
sendOn: 'course_id',
|
||||||
|
},
|
||||||
|
extractValue: true,
|
||||||
|
id: 'u:fd14fbccb8fc',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'submit',
|
||||||
|
label: '提交',
|
||||||
|
primary: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
feat: 'Insert',
|
||||||
|
dsType: 'api',
|
||||||
|
onEvent: {
|
||||||
|
submitSucc: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
componentId: 'u:148f700a4963',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'reload',
|
||||||
|
args: {
|
||||||
|
resetPage: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: 'dialog',
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
id: 'u:94b2f1f09462',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'cancel',
|
||||||
|
label: '取消',
|
||||||
|
id: 'u:0c74d636f491',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'confirm',
|
||||||
|
label: '确定',
|
||||||
|
primary: true,
|
||||||
|
id: 'u:2e60b730d920',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
confirmText: '确认清除分组吗?',
|
||||||
|
level: 'link',
|
||||||
|
icon: 'fa fa-trash text-danger',
|
||||||
|
size: 'md',
|
||||||
|
tooltip: '清除分组',
|
||||||
|
tooltipPlacement: 'top',
|
||||||
|
hiddenOn: '${!studentgroup_id}',
|
||||||
|
iconClassName: 'pull-left',
|
||||||
|
className: 'p-r-none p-l-none',
|
||||||
|
id: 'u:e719d85aa542',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
outputVar: 'responseResult',
|
||||||
|
actionType: 'ajax',
|
||||||
|
options: {},
|
||||||
|
api: {
|
||||||
|
url: 'rest/user_orgs?user_id=eq.$student_id&organization_id=eq.$studentgroup_id',
|
||||||
|
method: 'delete',
|
||||||
|
requestAdaptor: '',
|
||||||
|
adaptor: '',
|
||||||
|
messages: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentId: 'u:148f700a4963',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'reload',
|
||||||
|
args: {
|
||||||
|
resetPage: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
placeholder: '-',
|
||||||
|
width: 200,
|
||||||
|
id: 'u:b59ecbce78a6',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
name: 'grp',
|
||||||
|
bodyClassName: '',
|
||||||
|
title: '',
|
||||||
|
initFetch: true,
|
||||||
|
columnsTogglable: true,
|
||||||
|
id: 'u:148f700a4963',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
title: '',
|
||||||
|
messages: {},
|
||||||
|
id: 'u:9e76719da6ac',
|
||||||
|
};
|
||||||
|
|
||||||
|
export { schema };
|
||||||
525
src/pages/schema/centre/plan/project.schema.ts
Normal file
525
src/pages/schema/centre/plan/project.schema.ts
Normal file
@@ -0,0 +1,525 @@
|
|||||||
|
const schema = {
|
||||||
|
type: 'page',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'crud',
|
||||||
|
messages: {},
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/projects?select=*&organization_id=eq.${centre_id}&semester_id=eq.${currentSemester}&order=code',
|
||||||
|
data: {
|
||||||
|
page: '$page',
|
||||||
|
perPage: '$perPage',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
headerToolbar: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
id: 'u:b88c442cf1c9',
|
||||||
|
align: 'right',
|
||||||
|
label: '添加',
|
||||||
|
icon: 'fa fa-plus',
|
||||||
|
level: 'default',
|
||||||
|
className: 'm-l-xs',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '添加实验',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'rest/projects',
|
||||||
|
data: {
|
||||||
|
code: '${project_code}',
|
||||||
|
name: '${project_name}',
|
||||||
|
intro: '${project_intro}',
|
||||||
|
organization_id: '${centre_id}',
|
||||||
|
type: '${type}',
|
||||||
|
free_schedule: '${free_schedule}',
|
||||||
|
},
|
||||||
|
dataType: 'json',
|
||||||
|
requestAdaptor:
|
||||||
|
'if(api.data.type===\'examination\') {\r\n api.data.score_item=[{"item": "exp_preparation", "label": "实验预习", "weight": 1}];\r\n}\r\nreturn api;',
|
||||||
|
},
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
label: '编号',
|
||||||
|
name: 'project_code',
|
||||||
|
value: '',
|
||||||
|
required: true,
|
||||||
|
mode: 'normal',
|
||||||
|
id: 'u:4a4471a8f6fd',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '名称',
|
||||||
|
type: 'input-text',
|
||||||
|
name: 'project_name',
|
||||||
|
value: '',
|
||||||
|
required: true,
|
||||||
|
mode: 'normal',
|
||||||
|
id: 'u:5d11604bb560',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '类型',
|
||||||
|
type: 'select',
|
||||||
|
name: 'type',
|
||||||
|
required: true,
|
||||||
|
mode: 'normal',
|
||||||
|
checkAll: false,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/dicts?select=dictkey,dictvalue&typecode=eq.012',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: {\r\n ...payload.data,\r\n items: payload.data.items.map(item => {\r\n return {\r\n label: item.dictvalue,\r\n value: item.dictkey\r\n }\r\n })\r\n }\r\n}',
|
||||||
|
},
|
||||||
|
value: 'experiment',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: '实验课',
|
||||||
|
value: 'experiment',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:4f93120dc92a',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '学生自主安排时间',
|
||||||
|
type: 'checkbox',
|
||||||
|
name: 'free_schedule',
|
||||||
|
mode: 'inline',
|
||||||
|
value: false,
|
||||||
|
id: 'u:d8de66ea2a6b',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '描述',
|
||||||
|
type: 'input-rich-text',
|
||||||
|
name: 'project_intro',
|
||||||
|
mode: 'normal',
|
||||||
|
options: {
|
||||||
|
menubar: false,
|
||||||
|
},
|
||||||
|
id: 'u:41a4ab0a0f14',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:87d3612f0e3f',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'submit',
|
||||||
|
label: '提交',
|
||||||
|
primary: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
feat: 'Insert',
|
||||||
|
dsType: 'api',
|
||||||
|
onEvent: {
|
||||||
|
submitSucc: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
componentId: 'u:faff85507083',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'reload',
|
||||||
|
args: {
|
||||||
|
resetPage: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
id: 'u:d6cc5749dac1',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'cancel',
|
||||||
|
label: '取消',
|
||||||
|
id: 'u:25b4e52d9f7a',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'confirm',
|
||||||
|
label: '确定',
|
||||||
|
primary: true,
|
||||||
|
id: 'u:6f9f855502d6',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'export-excel',
|
||||||
|
align: 'right',
|
||||||
|
label: '实验导出',
|
||||||
|
icon: 'fa fa-download',
|
||||||
|
level: 'primary',
|
||||||
|
id: 'u:d57d6b7f1525',
|
||||||
|
api: 'rest/projects?select=*,dicts:dicts!project_type_fk(dictkey,dictvalue)&organization_id=eq.$centre_id&semester_id=eq.$currentSemester&order=code',
|
||||||
|
filename: '实验',
|
||||||
|
exportColumns: [
|
||||||
|
{
|
||||||
|
label: '*编号',
|
||||||
|
name: 'code',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'name',
|
||||||
|
label: '*名称',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'dicts.dictvalue',
|
||||||
|
label: '*类型',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
syncLocation: false,
|
||||||
|
perPageAvailable: [10, 20, 30, 40, 50],
|
||||||
|
footerToolbar: [
|
||||||
|
{
|
||||||
|
type: 'pagination',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'switch-per-page',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'statistics',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
perPageField: 'perPage',
|
||||||
|
pageField: 'page',
|
||||||
|
mode: 'table',
|
||||||
|
affixHeader: true,
|
||||||
|
id: 'u:faff85507083',
|
||||||
|
name: 'score',
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'code',
|
||||||
|
type: 'text',
|
||||||
|
label: '编号',
|
||||||
|
id: 'u:bad42a88a366',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
name: 'name',
|
||||||
|
label: '名称',
|
||||||
|
id: 'u:d9f55c020ac5',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'tpl',
|
||||||
|
label: '评分项',
|
||||||
|
name: 'score_item',
|
||||||
|
tpl: "<% if (this.score_item.length > 0) {\n this.score_item.forEach(score => { %>\n <% if (score.item === 'exp_report') { %>\n <span class='label label-info' style='margin-right: 1px; font-size: smaller;'> <%= score.label %> (<%= score.weight %>)\n <% if (score.isRecorded) { %>\n <i class='fa fa-pencil'></i>\n <% } %>\n </span>\n <% } else if (score.item === 'exp_data') { %>\n <span class='label label-success' style='margin-right: 1px; font-size: smaller;'> <%= score.label %> (<%= score.weight %>)\n <% if (score.isRecorded) { %>\n <i class='fa fa-pencil'></i>\n <% } %>\n </span>\n <% } else if (score.item === 'exp_preparation') { %>\n <span class='label label-danger' style='margin-right: 1px; font-size: smaller;'> <%= score.label %> (<%= score.weight %>)\n <% if (score.isRecorded) { %>\n <i class='fa fa-pencil'></i>\n <% } %>\n </span>\n <% } else if (score.item === 'exp_operation') { %>\n <span class='label label-warning' style='margin-right: 1px; font-size: smaller;'> <%= score.label %> (<%= score.weight %>)\n <% if (score.isRecorded) { %>\n <i class='fa fa-pencil'></i>\n <% } %>\n </span>\n <% } else if (score.item === 'exp_notebook') { %>\n <span class='label' style='margin-right: 1px; background: purple; font-size: smaller;'> <%= score.label %> (<%= score.weight %>)\n <% if (score.isRecorded) { %>\n <i class='fa fa-pencil'></i>\n <% } %>\n </span>\n <% } else if (score.item === 'exp_process_assessment') { %>\n <span class='label' style='margin-right: 1px; background: orange; font-size: smaller;'> <%= score.label %> (<%= score.weight %>)\n <% if (score.isRecorded) { %>\n <i class='fa fa-pencil'></i>\n <% } %>\n </span>\n <% } else if (score.item === 'exp_team') { %>\n <span class='label' style='margin-right: 1px; background: pink; font-size: smaller;'> <%= score.label %> (<%= score.weight %>)\n <% if (score.isRecorded) { %>\n <i class='fa fa-pencil'></i>\n <% } %>\n </span>\n <% } else { %>\n <span class='label' style=\"margin-right: 1px; background: #374151; font-size: smaller;\"> <%= score.label %> (<%= score.weight %>)\n <% if (score.isRecorded) { %>\n <i class='fa fa-pencil'></i>\n <% } %>\n </span>\n <% } %>\n <% }) %>\n <% } %>",
|
||||||
|
inline: false,
|
||||||
|
id: 'u:6fb5baeecfab',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'operation',
|
||||||
|
label: '操作',
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
level: 'link',
|
||||||
|
size: 'md',
|
||||||
|
icon: 'fa fa-pencil text-info',
|
||||||
|
tooltip: '修改',
|
||||||
|
tooltipPlacement: 'top',
|
||||||
|
iconClassName: 'pull-left',
|
||||||
|
className: 'm-r-none m-l-none',
|
||||||
|
id: 'u:74e446e57e2b',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '修改实验',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
api: {
|
||||||
|
method: 'patch',
|
||||||
|
url: 'rest/projects?id=eq.${id}',
|
||||||
|
data: {
|
||||||
|
code: '${code}',
|
||||||
|
name: '${name}',
|
||||||
|
intro: '${intro}',
|
||||||
|
type: '${type}',
|
||||||
|
free_schedule: '${free_schedule}',
|
||||||
|
},
|
||||||
|
dataType: 'json',
|
||||||
|
},
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
label: '编号',
|
||||||
|
name: 'code',
|
||||||
|
value: '',
|
||||||
|
required: true,
|
||||||
|
mode: 'normal',
|
||||||
|
id: 'u:45350664b507',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '名称',
|
||||||
|
type: 'input-text',
|
||||||
|
name: 'name',
|
||||||
|
value: '',
|
||||||
|
required: true,
|
||||||
|
mode: 'normal',
|
||||||
|
id: 'u:8e70cec48464',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '类型',
|
||||||
|
type: 'select',
|
||||||
|
name: 'type',
|
||||||
|
required: true,
|
||||||
|
mode: 'normal',
|
||||||
|
options: [],
|
||||||
|
checkAll: false,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/dicts?select=dictkey,dictvalue&typecode=eq.012',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: {\r\n ...payload.data,\r\n items: payload.data.items.map(item => {\r\n return {\r\n label: item.dictvalue,\r\n value: item.dictkey\r\n }\r\n })\r\n }\r\n}',
|
||||||
|
},
|
||||||
|
id: 'u:425ae91adc74',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '学生自主安排时间',
|
||||||
|
type: 'checkbox',
|
||||||
|
name: 'free_schedule',
|
||||||
|
mode: 'inline',
|
||||||
|
id: 'u:b43e9dc2a55d',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '描述',
|
||||||
|
type: 'input-rich-text',
|
||||||
|
name: 'intro',
|
||||||
|
value: '',
|
||||||
|
mode: 'normal',
|
||||||
|
id: 'u:84e41b04cf8c',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:3c25e724c688',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'submit',
|
||||||
|
label: '提交',
|
||||||
|
primary: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
feat: 'Insert',
|
||||||
|
dsType: 'api',
|
||||||
|
onEvent: {
|
||||||
|
submitSucc: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
componentId: 'u:faff85507083',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'reload',
|
||||||
|
args: {
|
||||||
|
resetPage: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
id: 'u:98e4cae66fe9',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'cancel',
|
||||||
|
label: '取消',
|
||||||
|
id: 'u:8dddacfd03ef',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'confirm',
|
||||||
|
label: '确定',
|
||||||
|
primary: true,
|
||||||
|
id: 'u:9a7c3432ab97',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
confirmText: '确认删除"${name}(${code})"?',
|
||||||
|
level: 'link',
|
||||||
|
icon: 'fa fa-times text-danger',
|
||||||
|
size: 'md',
|
||||||
|
tooltip: '删除',
|
||||||
|
tooltipPlacement: 'top',
|
||||||
|
iconClassName: 'pull-left',
|
||||||
|
className: 'm-r-none m-l-none',
|
||||||
|
id: 'u:58e504e36911',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
outputVar: 'responseResult',
|
||||||
|
actionType: 'ajax',
|
||||||
|
options: {},
|
||||||
|
api: {
|
||||||
|
url: 'rest/projects/$id',
|
||||||
|
method: 'delete',
|
||||||
|
requestAdaptor: '',
|
||||||
|
adaptor: '',
|
||||||
|
messages: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
componentId: 'u:faff85507083',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'reload',
|
||||||
|
args: {
|
||||||
|
resetPage: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
icon: 'fa fa-cog text-warning',
|
||||||
|
level: 'link',
|
||||||
|
messages: {},
|
||||||
|
title: '报告模板',
|
||||||
|
size: 'md',
|
||||||
|
confirmText: '',
|
||||||
|
tooltip: '修改实验评分项',
|
||||||
|
tooltipPlacement: 'top',
|
||||||
|
className: 'm-r-none m-l-none',
|
||||||
|
iconClassName: 'pull-left',
|
||||||
|
id: 'u:a5fd11fac042',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
title: '修改实验评分项',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
api: {
|
||||||
|
method: 'patch',
|
||||||
|
url: 'rest/projects/${id}',
|
||||||
|
data: {
|
||||||
|
score_item: '$score_item',
|
||||||
|
},
|
||||||
|
requestAdaptor: '',
|
||||||
|
dataType: 'json',
|
||||||
|
},
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'projectscoreitem',
|
||||||
|
name: 'score_item',
|
||||||
|
api: {
|
||||||
|
url: 'rest/dicts?typecode=eq.007',
|
||||||
|
},
|
||||||
|
mode: 'normal',
|
||||||
|
id: 'u:e3a860ff8f80',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:3510789a5776',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'submit',
|
||||||
|
label: '提交',
|
||||||
|
primary: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
feat: 'Insert',
|
||||||
|
dsType: 'api',
|
||||||
|
onEvent: {
|
||||||
|
submitSucc: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
componentId: 'u:faff85507083',
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'reload',
|
||||||
|
args: {
|
||||||
|
resetPage: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: 'dialog',
|
||||||
|
closeOnEsc: true,
|
||||||
|
closeOnOutside: false,
|
||||||
|
showCloseButton: true,
|
||||||
|
size: 'md',
|
||||||
|
id: 'u:34a7904cefc0',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'cancel',
|
||||||
|
label: '取消',
|
||||||
|
id: 'u:6fd9b88723bf',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'confirm',
|
||||||
|
label: '确定',
|
||||||
|
primary: true,
|
||||||
|
id: 'u:457223ebeaee',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
placeholder: '-',
|
||||||
|
id: 'u:33cc39b76ad4',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
bodyClassName: '',
|
||||||
|
initApi: '',
|
||||||
|
initFetch: '',
|
||||||
|
label: '名称',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:b7c1c11acda6',
|
||||||
|
};
|
||||||
|
|
||||||
|
export { schema };
|
||||||
69
src/pages/schema/centre/plan/textbook.schema.ts
Normal file
69
src/pages/schema/centre/plan/textbook.schema.ts
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
const schema = {
|
||||||
|
type: 'page',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
label: '数字化教材名称',
|
||||||
|
mode: 'horizontal',
|
||||||
|
required: true,
|
||||||
|
name: 'name',
|
||||||
|
id: 'u:1e67e22855ce',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'combo',
|
||||||
|
label: false,
|
||||||
|
name: 'cells',
|
||||||
|
required: true,
|
||||||
|
multiple: true,
|
||||||
|
addable: true,
|
||||||
|
removable: true,
|
||||||
|
removableMode: 'icon',
|
||||||
|
addBtn: {
|
||||||
|
label: '新增',
|
||||||
|
level: 'primary',
|
||||||
|
size: 'sm',
|
||||||
|
id: 'u:3300178a20b6',
|
||||||
|
},
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
type: 'vditor',
|
||||||
|
name: 'source',
|
||||||
|
id: 'u:48cbfec9c64d',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:1e67e22855be',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 'u:ccd0d1410b18',
|
||||||
|
feat: 'View',
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'rest/test',
|
||||||
|
data: {
|
||||||
|
cells: '$cells',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'textbook-submit',
|
||||||
|
label: '提交',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
wrapWithPanel: true,
|
||||||
|
dsType: 'api',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
title: '',
|
||||||
|
id: 'u:9e76719da6ac',
|
||||||
|
messages: {},
|
||||||
|
asideResizor: false,
|
||||||
|
pullRefresh: {
|
||||||
|
disabled: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export { schema };
|
||||||
1143
src/pages/schema/centre/report/deduction.schema.ts
Normal file
1143
src/pages/schema/centre/report/deduction.schema.ts
Normal file
File diff suppressed because it is too large
Load Diff
1411
src/pages/schema/centre/report/index.schema.ts
Normal file
1411
src/pages/schema/centre/report/index.schema.ts
Normal file
File diff suppressed because it is too large
Load Diff
49
src/pages/schema/centre/report/instructions.schema.ts
Normal file
49
src/pages/schema/centre/report/instructions.schema.ts
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
const schema = {
|
||||||
|
type: 'page',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '使用说明',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
args: {
|
||||||
|
url: 'https://www.platosoft.org/doc/olms/plugin/mark.html',
|
||||||
|
},
|
||||||
|
actionType: 'url',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
weight: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
size: 'md',
|
||||||
|
level: 'primary',
|
||||||
|
block: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '进入批阅',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
args: {
|
||||||
|
url: '/check',
|
||||||
|
},
|
||||||
|
actionType: 'url',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
weight: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
level: 'primary',
|
||||||
|
blank: true,
|
||||||
|
className: 'm-l',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
title: '报告上传与在线批阅',
|
||||||
|
messages: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
export { schema };
|
||||||
1113
src/pages/schema/centre/report/template.schema.ts
Normal file
1113
src/pages/schema/centre/report/template.schema.ts
Normal file
File diff suppressed because it is too large
Load Diff
513
src/pages/schema/centre/schedule/auto.schema.ts
Normal file
513
src/pages/schema/centre/schedule/auto.schema.ts
Normal file
@@ -0,0 +1,513 @@
|
|||||||
|
const schema = {
|
||||||
|
type: 'page',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'scheduler-renderer',
|
||||||
|
name: 'scheduler',
|
||||||
|
body: [],
|
||||||
|
plan: {
|
||||||
|
type: 'button',
|
||||||
|
label: '按钮',
|
||||||
|
actionType: 'drawer',
|
||||||
|
dialog: { title: '系统提示', body: '对你点击了' },
|
||||||
|
drawer: {
|
||||||
|
type: 'drawer',
|
||||||
|
title: '弹框标题',
|
||||||
|
body: [
|
||||||
|
{ type: 'tpl', tpl: '<p>对,你刚刚点击了</p>', inline: false },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
planlistbutton: {
|
||||||
|
type: 'button',
|
||||||
|
label: '',
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '排课计划',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'service',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '添加计划',
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '添加计划',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'wizard',
|
||||||
|
reload: 'plancrud',
|
||||||
|
steps: [
|
||||||
|
{
|
||||||
|
title: '计划设置',
|
||||||
|
mode: 'normal',
|
||||||
|
controls: [
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '计划名称',
|
||||||
|
name: 'name',
|
||||||
|
mode: 'normal',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'date-range',
|
||||||
|
label: '日期范围',
|
||||||
|
name: 'date',
|
||||||
|
required: true,
|
||||||
|
format: 'YYYY-MM-DD',
|
||||||
|
minDate: '${semester.since}',
|
||||||
|
maxDate: '${semester.to}',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'number',
|
||||||
|
label: '老师每周最多上课数量',
|
||||||
|
name: 'teacherFreqWeekly',
|
||||||
|
required: true,
|
||||||
|
mode: 'normal',
|
||||||
|
min: '1',
|
||||||
|
step: 1,
|
||||||
|
value: 10,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'number',
|
||||||
|
label: '老师每天最多上课数量',
|
||||||
|
name: 'teacherFreqDaily',
|
||||||
|
mode: 'normal',
|
||||||
|
required: true,
|
||||||
|
min: '1',
|
||||||
|
step: 1,
|
||||||
|
value: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'number',
|
||||||
|
label: '老师同时上课数量',
|
||||||
|
name: 'maxConcurrentOfTeacher',
|
||||||
|
mode: 'normal',
|
||||||
|
required: true,
|
||||||
|
min: '1',
|
||||||
|
step: 1,
|
||||||
|
value: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'number',
|
||||||
|
name: 'maxConcurrent',
|
||||||
|
mode: 'normal',
|
||||||
|
label: '同一时段最多排课数量',
|
||||||
|
required: true,
|
||||||
|
value: 4,
|
||||||
|
min: '1',
|
||||||
|
step: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'number',
|
||||||
|
name: 'maxFreqWeekly',
|
||||||
|
mode: 'normal',
|
||||||
|
label: '学生每周上课数',
|
||||||
|
required: true,
|
||||||
|
value: 1,
|
||||||
|
min: '1',
|
||||||
|
step: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'switch',
|
||||||
|
name: 'fixTeacherMode',
|
||||||
|
mode: 'normal',
|
||||||
|
label: '',
|
||||||
|
required: true,
|
||||||
|
value: false,
|
||||||
|
option: ' 教师跟班模式',
|
||||||
|
optionAtLeft: false,
|
||||||
|
trueValue: true,
|
||||||
|
falseValue: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '资源设置',
|
||||||
|
controls: [
|
||||||
|
{
|
||||||
|
type: 'course-list',
|
||||||
|
label: '课程',
|
||||||
|
name: 'courselist',
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/courses?select=id,name,course2projects(projects(id,name,validRoomList,preSubjectList)),course2orgs(orgs(id,name, validTimeslotList:timeslot_class_id_fkey(id,date,period:periods(id,name,startTime:start_time,endTime:end_time))))&organization_id=eq.${centre_id}&semester_id=eq.${currentSemester}&order=code',
|
||||||
|
},
|
||||||
|
required: true,
|
||||||
|
multiple: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
mode: 'normal',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mode: 'normal',
|
||||||
|
title: '工作量设置',
|
||||||
|
controls: [
|
||||||
|
{
|
||||||
|
type: 'workload',
|
||||||
|
name: 'workload',
|
||||||
|
source:
|
||||||
|
'rest/users?select=id,name:name,role,subjectList,studentGroupList,user_orgs(organization_id),timeslotList:timeslot_teacher_id_fkey(id,date,period:periods(id,name,startTime:start_time,endTime:end_time)),secondChoiceTimeslotList:timeslot_teacher_secondary_id_fkey(id,date,period:periods(id,name,startTime:start_time,endTime:end_time))&role=eq.teacher&user_orgs.organization_id=eq.${centre_id}&order=code',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
mode: 'horizontal',
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'rest/schedule_plans',
|
||||||
|
requestAdaptor:
|
||||||
|
"return {\r\n ...api,\r\n data: {\r\n name: api.data.name,\r\n date: api.data.date,\r\n status: '待求解',\r\n organization_id: api.data.organization_id,\r\n problem: {\r\n problemConfig: {\r\n fixTeacherMode: api.data.fixTeacherMode,\r\n maxConcurrent: api.data.maxConcurrent,\r\n maxConcurrentOfTeacher: api.data.maxConcurrentOfTeacher,\r\n maxFreqWeekly: api.data.maxFreqWeekly,\r\n teacherFreqWeekly: api.data.teacherFreqWeekly,\r\n teacherFreqDaily: api.data.teacherFreqDaily,\r\n excludeRoomTime: api.data.excludeRoomTime,\r\n excludeTeacherStudentGroup: api.data.excludeTeacherStudentGroup,\r\n excludeTeacherSubject: api.data.excludeTeacherSubject,\r\n excludeTeacherTime: api.data.excludeTeacherTime,\r\n },\r\n courseList: api.data.courselist.map((item) => {\r\n return {\r\n id: item.id,\r\n name: item.name,\r\n subjectList: item.subjectList.map((e) => {\r\n return {\r\n id: e.id,\r\n name: e.name,\r\n abbreviation: item.name,\r\n validRoomList: e.validRoomList,\r\n preSubjectList: e.preSubjectList\r\n };\r\n }),\r\n studentGroupList: item.studentGroupList.map((e) => {\r\n return {\r\n id: e.id,\r\n name: e.name,\r\n validTimeslotList: e.validTimeslotList,\r\n };\r\n }),\r\n };\r\n }),\r\n validTeacherList: api.data.workload.filter(item => item.workload > 0).map((item) => {\r\n return {\r\n id: item.id,\r\n name: item.name,\r\n workload: item.workload,\r\n timeslotList: item.timeslotList,\r\n secondChoiceTimeslotList: item.secondChoiceTimeslotList,\r\n subjectList: item.subjectList,\r\n studentGroupList: item.studentGroupList,\r\n };\r\n }),\r\n },\r\n },\r\n};\r\n",
|
||||||
|
data: {
|
||||||
|
'&': '$$',
|
||||||
|
organization_id: '${centre_id}',
|
||||||
|
excludeRoomTime: '${excludeRoomTime}',
|
||||||
|
excludeTeacherStudentGroup:
|
||||||
|
'${excludeTeacherStudentGroup}',
|
||||||
|
excludeTeacherSubject: '${excludeTeacherSubject}',
|
||||||
|
excludeTeacherTime: '${excludeTeacherTime}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
name: 'stepper',
|
||||||
|
actionNextSaveLabel: '下一步',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
actions: [],
|
||||||
|
data: {
|
||||||
|
currentSemester: '${currentSemester}',
|
||||||
|
centre_id: '${centre_id}',
|
||||||
|
semester: '${semester}',
|
||||||
|
excludeRoomTime: '${excludeRoomTime}',
|
||||||
|
excludeTeacherStudentGroup:
|
||||||
|
'${excludeTeacherStudentGroup}',
|
||||||
|
excludeTeacherSubject: '${excludeTeacherSubject}',
|
||||||
|
excludeTeacherTime: '${excludeTeacherTime}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
className: 'm-b-sm ',
|
||||||
|
block: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'crud',
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/schedule_plans?semester_id=eq.${currentSemester}&organization_id=eq.${centre_id}&order=updated_at.desc',
|
||||||
|
data: { '&': '$$', page: '${page}', perPage: '${perPage}' },
|
||||||
|
},
|
||||||
|
columns: [
|
||||||
|
{ name: 'name', label: '排课计划', type: 'text' },
|
||||||
|
{ type: 'text', label: '状态', name: 'status' },
|
||||||
|
{
|
||||||
|
type: 'operation',
|
||||||
|
label: '操作',
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
label: '选择',
|
||||||
|
type: 'button',
|
||||||
|
visibleOn: '!this.is_current',
|
||||||
|
actionType: 'ajax',
|
||||||
|
confirmText: '确认切换排课计划?',
|
||||||
|
className: '',
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/schedule_plans/${id}',
|
||||||
|
},
|
||||||
|
size: 'sm',
|
||||||
|
level: 'primary',
|
||||||
|
reload: 'scheduler?plan=${id}',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
visibleOn: '!this.is_current',
|
||||||
|
label: '编辑',
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
title: '修改计划',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'wizard',
|
||||||
|
reload: 'plancrud',
|
||||||
|
api: {
|
||||||
|
method: 'patch',
|
||||||
|
url: 'rest/schedule_plans?id=eq.${id}',
|
||||||
|
requestAdaptor:
|
||||||
|
"return {\r\n ...api,\r\n data: {\r\n name: api.data.name,\r\n date: api.data.date,\r\n status: '待求解',\r\n organization_id: api.data.organization_id,\r\n problem: {\r\n problemConfig: {\r\n fixTeacherMode: api.data.fixTeacherMode,\r\n maxConcurrent: api.data.maxConcurrent,\r\n maxConcurrentOfTeacher: api.data.maxConcurrentOfTeacher,\r\n maxFreqWeekly: api.data.maxFreqWeekly,\r\n teacherFreqWeekly: api.data.teacherFreqWeekly,\r\n teacherFreqDaily: api.data.teacherFreqDaily,\r\n excludeRoomTime: api.data.excludeRoomTime,\r\n excludeTeacherStudentGroup: api.data.excludeTeacherStudentGroup,\r\n excludeTeacherSubject: api.data.excludeTeacherSubject,\r\n excludeTeacherTime: api.data.excludeTeacherTime,\r\n },\r\n courseList: api.data.courselist.map((item) => {\r\n return {\r\n id: item.id,\r\n name: item.name,\r\n subjectList: item.subjectList.map((e) => {\r\n return {\r\n id: e.id,\r\n name: e.name,\r\n abbreviation: item.name,\r\n validRoomList: e.validRoomList,\r\n preSubjectList: e.preSubjectList\r\n };\r\n }),\r\n studentGroupList: item.studentGroupList.map((e) => {\r\n return {\r\n id: e.id,\r\n name: e.name,\r\n validTimeslotList: e.validTimeslotList\r\n\r\n };\r\n }),\r\n };\r\n }),\r\n validTeacherList: api.data.workload.filter(item => item.workload > 0).map((item) => {\r\n return {\r\n id: item.id,\r\n name: item.name,\r\n workload: item.workload,\r\n timeslotList: item.timeslotList,\r\n secondChoiceTimeslotList: item.secondChoiceTimeslotList,\r\n subjectList: item.subjectList,\r\n studentGroupList: item.studentGroupList,\r\n };\r\n }),\r\n },\r\n },\r\n};\r\n",
|
||||||
|
data: {
|
||||||
|
'&': '$$',
|
||||||
|
organization_id: '${centre_id}',
|
||||||
|
excludeRoomTime: '${excludeRoomTime}',
|
||||||
|
excludeTeacherStudentGroup:
|
||||||
|
'${excludeTeacherStudentGroup}',
|
||||||
|
excludeTeacherSubject:
|
||||||
|
'${excludeTeacherSubject}',
|
||||||
|
excludeTeacherTime: '${excludeTeacherTime}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
steps: [
|
||||||
|
{
|
||||||
|
title: '计划设置',
|
||||||
|
mode: 'normal',
|
||||||
|
controls: [
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '计划名称',
|
||||||
|
name: 'name',
|
||||||
|
mode: 'normal',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'date-range',
|
||||||
|
label: '日期范围',
|
||||||
|
name: 'date',
|
||||||
|
required: true,
|
||||||
|
format: 'YYYY-MM-DD',
|
||||||
|
minDate: '${semester.since}',
|
||||||
|
maxDate: '${semester.to}',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'number',
|
||||||
|
label: '老师每周最多上课数量',
|
||||||
|
name: 'teacherFreqWeekly',
|
||||||
|
required: true,
|
||||||
|
mode: 'normal',
|
||||||
|
min: '1',
|
||||||
|
step: 1,
|
||||||
|
value: 10,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'number',
|
||||||
|
label: '老师每天最多上课数量',
|
||||||
|
name: 'teacherFreqDaily',
|
||||||
|
mode: 'normal',
|
||||||
|
required: true,
|
||||||
|
min: '1',
|
||||||
|
step: 1,
|
||||||
|
value: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'number',
|
||||||
|
label: '老师同时上课数量',
|
||||||
|
name: 'maxConcurrentOfTeacher',
|
||||||
|
mode: 'normal',
|
||||||
|
required: true,
|
||||||
|
min: '1',
|
||||||
|
step: 1,
|
||||||
|
value: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'number',
|
||||||
|
name: 'maxConcurrent',
|
||||||
|
mode: 'normal',
|
||||||
|
label: '同一时段最多排课数量',
|
||||||
|
required: true,
|
||||||
|
value: 4,
|
||||||
|
min: '1',
|
||||||
|
step: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'number',
|
||||||
|
name: 'maxFreqWeekly',
|
||||||
|
mode: 'normal',
|
||||||
|
label: '学生每周上课数',
|
||||||
|
required: true,
|
||||||
|
value: 1,
|
||||||
|
min: '1',
|
||||||
|
step: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'switch',
|
||||||
|
name: 'fixTeacherMode',
|
||||||
|
mode: 'normal',
|
||||||
|
label: '',
|
||||||
|
required: true,
|
||||||
|
value: false,
|
||||||
|
option: ' 教师跟班模式',
|
||||||
|
optionAtLeft: false,
|
||||||
|
trueValue: true,
|
||||||
|
falseValue: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '资源设置',
|
||||||
|
controls: [
|
||||||
|
{
|
||||||
|
type: 'course-list',
|
||||||
|
label: '课程',
|
||||||
|
name: 'courselist',
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/courses?select=id,name,course2projects(projects(id,name,validRoomList,preSubjectList)),course2orgs(orgs(id,name, validTimeslotList:timeslot_class_id_fkey(id,date,period:periods(id,name,startTime:start_time,endTime:end_time))))&organization_id=eq.${centre_id}&semester_id=eq.${currentSemester}&order=code',
|
||||||
|
},
|
||||||
|
required: true,
|
||||||
|
multiple: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
mode: 'normal',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mode: 'normal',
|
||||||
|
title: '工作量设置',
|
||||||
|
controls: [
|
||||||
|
{
|
||||||
|
type: 'workload',
|
||||||
|
name: 'workload',
|
||||||
|
source:
|
||||||
|
'rest/users?select=id,name:name,role,subjectList,studentGroupList,user_orgs(organization_id),timeslotList:timeslot_teacher_id_fkey(id,date,period:periods(id,name,startTime:start_time,endTime:end_time)),secondChoiceTimeslotList:timeslot_teacher_secondary_id_fkey(id,date,period:periods(id,name,startTime:start_time,endTime:end_time))&role=eq.teacher&user_orgs.organization_id=eq.${centre_id}&order=code',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
mode: 'horizontal',
|
||||||
|
name: 'stepper',
|
||||||
|
actionNextSaveLabel: '下一步',
|
||||||
|
initApi: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/schedule_plans?id=eq.${id}',
|
||||||
|
adaptor:
|
||||||
|
'const data = payload.data.items[0]\r\nreturn {\r\n data: {\r\n ...data.problem,\r\n ...data.problem.problemConfig,\r\n courselist: data.problem.courseList,\r\n workload: data.problem.validTeacherList,\r\n id: data.id,\r\n name: data.name,\r\n date: data.date\r\n }\r\n}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: 'dialog',
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
actions: [],
|
||||||
|
data: {
|
||||||
|
'&': '$$',
|
||||||
|
name: '${name}',
|
||||||
|
maxConcurrent:
|
||||||
|
'${config.problemConfig.maxConcurrent}',
|
||||||
|
teacherFreqDaily:
|
||||||
|
'${config.problemConfig.teacherFreqDaily}',
|
||||||
|
date: '${config.date}',
|
||||||
|
maxConcurrentOfTeacher:
|
||||||
|
'${config.problemConfig.maxConcurrentOfTeacher}',
|
||||||
|
maxFreqWeekly:
|
||||||
|
'${config.problemConfig.maxFreqWeekly}',
|
||||||
|
fixTeacherMode:
|
||||||
|
'${config.problemConfig.fixTeacherMode}',
|
||||||
|
courselist: '${config.courseList}',
|
||||||
|
workload: '${config.validTeacherList}',
|
||||||
|
centre_id: '${centre_id}',
|
||||||
|
id: '${id}',
|
||||||
|
currentSemester: '${currentSemester}',
|
||||||
|
semester: '${semester}',
|
||||||
|
teacherFreqWeekly:
|
||||||
|
'${config.problemConfig.teacherFreqWeekly}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
size: 'sm',
|
||||||
|
icon: 'fa fa-pencil',
|
||||||
|
tooltip: '修改计划配置',
|
||||||
|
tooltipPlacement: 'bottom',
|
||||||
|
className: 'no-border',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
visibleOn: '!this.is_current',
|
||||||
|
label: '删除',
|
||||||
|
actionType: 'ajax',
|
||||||
|
size: 'sm',
|
||||||
|
confirmText: '确认删除该计划?',
|
||||||
|
api: {
|
||||||
|
method: 'delete',
|
||||||
|
url: 'rest/schedule_plans?id=eq.${id}',
|
||||||
|
},
|
||||||
|
reload: 'plancrud',
|
||||||
|
level: 'danger',
|
||||||
|
icon: 'fa fa-trash',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'tpl',
|
||||||
|
tpl: '当前计划',
|
||||||
|
inline: true,
|
||||||
|
visibleOn: 'this.is_current',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
messages: {},
|
||||||
|
name: 'plancrud',
|
||||||
|
syncLocation: false,
|
||||||
|
defaultParams: {},
|
||||||
|
filter: null,
|
||||||
|
headerToolbar: [{ type: 'bulk-actions' }],
|
||||||
|
perPageAvailable: '',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
messages: {},
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/config?key=eq.system',
|
||||||
|
adaptor:
|
||||||
|
'let config = payload.data.items && payload.data.items.length > 0 ? payload.data.items[0].value : null\r\nreturn {\r\n data: {\r\n excludeRoomTime: config ? config.excludeRoomTime : true,\r\n excludeTeacherStudentGroup: config ? config.excludeTeacherStudentGroup : true,\r\n excludeTeacherSubject: config ? config.excludeTeacherSubject : true,\r\n excludeTeacherTime: config ? config.excludeTeacherTime : true,\r\n }\r\n}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
actions: [],
|
||||||
|
},
|
||||||
|
size: 'xs',
|
||||||
|
icon: 'fa fa-list',
|
||||||
|
tooltip: '查看计划列表',
|
||||||
|
tooltipPlacement: 'bottom',
|
||||||
|
className: 'no-border',
|
||||||
|
},
|
||||||
|
planstartbutton: {
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'ajax',
|
||||||
|
reload: 'window',
|
||||||
|
target: '',
|
||||||
|
blank: true,
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'rest/timetable/${id}/solve',
|
||||||
|
dataType: 'json',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
planstopbutton: {
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'ajax',
|
||||||
|
reload: 'window',
|
||||||
|
target: '',
|
||||||
|
confirmText: '确认停止计算?',
|
||||||
|
blank: true,
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'rest/timetable/${id}/stopSolving',
|
||||||
|
dataType: 'json',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plansavebutton: {
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'ajax',
|
||||||
|
reload: '',
|
||||||
|
target: '',
|
||||||
|
confirmText: '确认生效该计划安排的场次?',
|
||||||
|
blank: true,
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'rest/schedules',
|
||||||
|
dataType: 'json',
|
||||||
|
requestAdaptor:
|
||||||
|
'return {\r\n ...api,\r\n data: api.data.schedules\r\n}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
title: '',
|
||||||
|
messages: {},
|
||||||
|
bodyClassName: 'p-none flex',
|
||||||
|
className: 'bg-white h-full',
|
||||||
|
toolbar: [],
|
||||||
|
aside: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
export { schema };
|
||||||
280
src/pages/schema/centre/schedule/class_settings.schema.ts
Normal file
280
src/pages/schema/centre/schedule/class_settings.schema.ts
Normal file
@@ -0,0 +1,280 @@
|
|||||||
|
const schema = {
|
||||||
|
type: 'page',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
submitOnChange: true,
|
||||||
|
reload: 'class_set?id=$orgSelect&org=$org',
|
||||||
|
wrapWithPanel: false,
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'tree-select',
|
||||||
|
name: 'orgSelect',
|
||||||
|
label: '查询',
|
||||||
|
mode: 'inline',
|
||||||
|
size: 'lg',
|
||||||
|
clearable: true,
|
||||||
|
searchable: true,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/orgs?select=*,course2orgs(*,courses(*))&path=cd.root&course2orgs.courses.semester_id=eq.${currentSemester}&type=in.(school,centre,faculty)&order=name,code',
|
||||||
|
adaptor:
|
||||||
|
"const recursive = id => {\r\n let nodes = payload.data.items.filter(x => {\r\n return x.parent === id\r\n })\r\n return nodes.map(item => {\r\n return {\r\n ...item,\r\n label: item.name,\r\n value: `${item.id}`,\r\n children: recursive(item.id)\r\n }\r\n })\r\n}\r\nlet school = payload.data.items.find(x => x.type === 'school');\r\nreturn {\r\n ...payload,\r\n data: [{\r\n label: school.name,\r\n value: `${school.id}`,\r\n children: recursive(school.id)\r\n }]\r\n}\r\n",
|
||||||
|
},
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
options: [],
|
||||||
|
initiallyOpen: false,
|
||||||
|
unfoldedLevel: 2,
|
||||||
|
multiple: true,
|
||||||
|
joinValues: true,
|
||||||
|
onlyChildren: true,
|
||||||
|
withChildren: true,
|
||||||
|
extractValue: false,
|
||||||
|
heightAuto: true,
|
||||||
|
virtualThreshold: false,
|
||||||
|
id: 'u:3224d44c5c5d',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input-text',
|
||||||
|
label: '组织或组织编号',
|
||||||
|
placeholder: '',
|
||||||
|
name: 'org',
|
||||||
|
size: 'md',
|
||||||
|
clearable: true,
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
id: 'u:89966cee9c0b',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
mode: 'inline',
|
||||||
|
debug: false,
|
||||||
|
id: 'u:254f488290d5',
|
||||||
|
feat: 'Insert',
|
||||||
|
},
|
||||||
|
{ type: 'divider', lineStyle: 'solid', id: 'u:c6f2f106da08' },
|
||||||
|
{
|
||||||
|
type: 'crud',
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/orgs?select=*,course2orgs!inner(*,courses!inner(*))&or=(name.like.*${org}*,code.like.*${org}*)&path=cd.root&type=in.(class,studentgroup,reelecclass)&course2orgs.courses.semester_id=eq.$currentSemester&order=name,code',
|
||||||
|
data: { page: '${page}', perPage: '${perPage}', parent: 'in.(${id})' },
|
||||||
|
adaptor: '',
|
||||||
|
requestAdaptor:
|
||||||
|
"if (api.query.parent === 'in.()') {\r\n api.url = api.url.replace('&parent=in.%28%29', '')\r\n}\r\n\r\nreturn {\r\n ...api\r\n}",
|
||||||
|
},
|
||||||
|
messages: {},
|
||||||
|
mode: 'cards',
|
||||||
|
card: {
|
||||||
|
type: 'card',
|
||||||
|
header: { title: '$name', subTitle: '$code' },
|
||||||
|
body: [],
|
||||||
|
toolbar: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '可用时间',
|
||||||
|
icon: 'fa fa-group',
|
||||||
|
iconClassName: '',
|
||||||
|
reload: '',
|
||||||
|
id: 'u:2681ac5e5b28',
|
||||||
|
editorState: 'default',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'timeslot-renderer',
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/timeslots?select=id,date,organization_id,class_id,periods(id,start_time,end_time)&class_id=eq.${id}&organization_id=eq.${centre_id}',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n data: {\r\n timeslots: payload.data.items.map(item => {\r\n return {\r\n id: item.id,\r\n date: item.date,\r\n semester_id: item.semester_id,\r\n organization_id: item.organization_id,\r\n class_id: item.class_id,\r\n period: item.periods\r\n }\r\n })\r\n }\r\n}',
|
||||||
|
},
|
||||||
|
copy: {
|
||||||
|
type: 'button',
|
||||||
|
label: '按钮',
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
title: '复制本周设置到其他周',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'rest/rpc/timeslots',
|
||||||
|
dataType: 'json',
|
||||||
|
headers: { Prefer: 'params=single-object' },
|
||||||
|
requestAdaptor:
|
||||||
|
'return {\r\n ...api,\r\n data: api.data.timeslotcopy\r\n}',
|
||||||
|
},
|
||||||
|
id: 'u:f4b826ee7ac0',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'timeslot-copy',
|
||||||
|
name: 'timeslotcopy',
|
||||||
|
mode: 'normal',
|
||||||
|
target: 'class',
|
||||||
|
id: 'u:ff2c4be14afe',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
actions: [
|
||||||
|
{ type: 'submit', label: '提交', primary: true },
|
||||||
|
],
|
||||||
|
feat: 'Insert',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: 'dialog',
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
id: 'u:c7de31e65b52',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'cancel',
|
||||||
|
label: '取消',
|
||||||
|
id: 'u:9451198740aa',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
actionType: 'confirm',
|
||||||
|
label: '确定',
|
||||||
|
primary: true,
|
||||||
|
id: 'u:f874015df55f',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
target: 'class',
|
||||||
|
id: 'u:8467642842c2',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
title: '班级时间设置',
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
size: 'md',
|
||||||
|
actions: [],
|
||||||
|
id: 'u:5ddbcf531f34',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: ' 预览',
|
||||||
|
icon: 'fa fa-eye',
|
||||||
|
level: 'link',
|
||||||
|
size: 'md',
|
||||||
|
iconClassName: '',
|
||||||
|
id: 'u:f44e5cfab0c3',
|
||||||
|
editorState: 'default',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '班级可用时间',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'tpl',
|
||||||
|
tpl: '<span class="label" style="background: #e5e7eb;">X</span>\n<span style="vertical-align: middle;">不可用时间</span>\n<span class="label label-info">X</span>\n<span style="vertical-align: middle;">可用时间</span>',
|
||||||
|
inline: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'crud',
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/periods?select=*,timeslots(*)×lots.organization_id=eq.$centre_id×lots.date=gte.${semester.since}×lots.date=lte.${semester.to}×lots.class_id=eq.$id&order=code',
|
||||||
|
adaptor:
|
||||||
|
"let items = []\r\nconst week_list = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']\r\nconst oneday = 24 * 60 * 60 * 1000\r\nconst get_week_num = (start, end) => {\r\n let s = new Date(start)\r\n let s_ms = s.getTime()\r\n let s_day = s.getDay() ? s.getDay() : 7\r\n s.setTime(s_ms - (s_day - 1) * oneday)\r\n s_ms = s.getTime()\r\n let e = new Date(end)\r\n let e_ms = e.getTime()\r\n let e_day = e.getDay() ? e.getDay() : 7\r\n return {\r\n sem_start: s,\r\n day: e_day,\r\n week_num: Math.ceil(((e_ms - s_ms) / oneday + 1) / 7)\r\n }\r\n}\r\nlet start = /(?<=\\[date\\]\\[0\\]=gte\\.)\\d+-\\d+-\\d+/g.exec(api.url)[0]\r\nlet end = /(?<=\\[date\\]\\[1\\]=lte\\.)\\d+-\\d+-\\d+/g.exec(api.url)[0]\r\nconst { sem_start, week_num } = get_week_num(start, end)\r\nfor (let i = 0; i < 7; i++) {\r\n let date_temp = new Date(sem_start)\r\n let date_temp_ms = date_temp.getTime()\r\n payload.data.items.map(x => {\r\n const [h, m, s] = x.start_time.split(':')\r\n return {\r\n ...x,\r\n cmp_time: new Date(2020, 0, 1, h, m, s)\r\n }\r\n }).sort((a, b) => {\r\n return a.cmp_time - b.cmp_time\r\n }).forEach(item => {\r\n let week_num_list = []\r\n for (let j = 0; j < week_num; j++) {\r\n date_temp.setTime(date_temp_ms + j * 7 * oneday + i * oneday)\r\n week_num_list.push({\r\n week: j + 1,\r\n date: null,\r\n tpl: \"<span title='\".concat(date_temp.toISOString().split('T')[0], \"' class='label' style='background: #e5e7eb;'>\", j + 1, \"</span>\")\r\n })\r\n }\r\n items.push({\r\n day: {\r\n lab: week_list[i],\r\n val: i + 1\r\n },\r\n period: {\r\n lab: item.name,\r\n val: item.id\r\n },\r\n weeks: week_num_list\r\n })\r\n })\r\n}\r\nconst row_mem = payload.data.items.length\r\npayload.data.items.map(x => {\r\n const [h, m, s] = x.start_time.split(':')\r\n return {\r\n ...x,\r\n cmp_time: new Date(2020, 0, 1, h, m, s)\r\n }\r\n}).sort((a, b) => {\r\n return a.cmp_time - b.cmp_time\r\n}).forEach((item, index) => {\r\n item.timeslots && item.timeslots.forEach(i => {\r\n const { day, week_num } = get_week_num(sem_start, i.date)\r\n items[(day - 1) * row_mem + index].weeks[week_num - 1].date = i.date\r\n items[(day - 1) * row_mem + index].weeks[week_num - 1].id = i.id\r\n const week = items[(day - 1) * row_mem + index].weeks[week_num - 1].week\r\n items[(day - 1) * row_mem + index].weeks[week_num - 1].tpl = \"<span title='\".concat(i.date, \"' class='label label-primary'>\", week, \"</span>\")\r\n })\r\n})\r\nreturn {\r\n ...payload,\r\n data: {\r\n items: items\r\n }\r\n}",
|
||||||
|
requestAdaptor: '',
|
||||||
|
},
|
||||||
|
messages: {},
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'day.lab',
|
||||||
|
label: '',
|
||||||
|
type: 'text',
|
||||||
|
inline: true,
|
||||||
|
className: 'common-padding',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '',
|
||||||
|
name: 'period.lab',
|
||||||
|
placeholder: '-',
|
||||||
|
className: 'common-padding',
|
||||||
|
inline: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'weeks',
|
||||||
|
label: '',
|
||||||
|
type: 'each',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
type: 'tpl',
|
||||||
|
tpl: '<%= data.tpl %>',
|
||||||
|
inline: true,
|
||||||
|
className: 'm-r-xs',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
placeholder: '-',
|
||||||
|
className: 'common-padding',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
combineNum: 1,
|
||||||
|
columnsTogglable: false,
|
||||||
|
syncLocation: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
size: 'lg',
|
||||||
|
data: null,
|
||||||
|
bodyClassName: 'p-t-none',
|
||||||
|
actions: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
actionsCount: 3,
|
||||||
|
id: 'u:140b3d90b196',
|
||||||
|
},
|
||||||
|
syncLocation: false,
|
||||||
|
placeholder: '暂无数据',
|
||||||
|
columnsCount: 4,
|
||||||
|
name: 'class_set',
|
||||||
|
headerToolbar: [],
|
||||||
|
footerToolbar: [
|
||||||
|
{ type: 'pagination' },
|
||||||
|
{ type: 'switch-per-page' },
|
||||||
|
{ type: 'statistics' },
|
||||||
|
],
|
||||||
|
perPageAvailable: [20, 40, 80],
|
||||||
|
defaultParams: { perPage: 20 },
|
||||||
|
bulkActions: [],
|
||||||
|
itemActions: [],
|
||||||
|
loadDataOnce: false,
|
||||||
|
id: 'u:06cd3a22ee0c',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
messages: {},
|
||||||
|
title: '',
|
||||||
|
cssVars: { '--Checkbox-onDisabled-color': 'transparent' },
|
||||||
|
id: 'u:1cbc663fae2b',
|
||||||
|
};
|
||||||
|
|
||||||
|
export { schema };
|
||||||
4068
src/pages/schema/centre/schedule/index.schema.ts
Normal file
4068
src/pages/schema/centre/schedule/index.schema.ts
Normal file
File diff suppressed because one or more lines are too long
289
src/pages/schema/centre/schedule/lists.schema.ts
Normal file
289
src/pages/schema/centre/schedule/lists.schema.ts
Normal file
@@ -0,0 +1,289 @@
|
|||||||
|
const schema = {
|
||||||
|
type: 'page',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
className: 'm-b-sm',
|
||||||
|
submitOnChange: true,
|
||||||
|
submitOnInit: true,
|
||||||
|
reload:
|
||||||
|
'manage_list?project_id=$project_id&teacher_id=$teacher_id&location_id=$location_id&date=$date&period_id=$period_id',
|
||||||
|
wrapWithPanel: false,
|
||||||
|
mode: 'inline',
|
||||||
|
name: 'filter',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'group',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
label: '项目',
|
||||||
|
name: 'project_id',
|
||||||
|
mode: 'inline',
|
||||||
|
clearable: true,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/projects?organization_id=eq.$centre_id&semester_id=eq.$currentSemester&order=name',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: payload.data.items.map(item => {\r\n return {\r\n label: item.name,\r\n value: "eq.".concat(item.id)\r\n }\r\n })\r\n}',
|
||||||
|
},
|
||||||
|
checkAll: false,
|
||||||
|
size: 'md',
|
||||||
|
searchable: true,
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
className: 'm-l-sm',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'group',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'input-date-range',
|
||||||
|
name: 'date',
|
||||||
|
mode: 'inline',
|
||||||
|
label: '日期',
|
||||||
|
clearable: true,
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
className: 'm-l-sm',
|
||||||
|
value: '',
|
||||||
|
format: 'YYYY-MM-DD',
|
||||||
|
ranges:
|
||||||
|
'yesterday,today,7daysago,prevweek,thismonth,prevmonth,prevquarter',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '节次',
|
||||||
|
type: 'select',
|
||||||
|
name: 'period_id',
|
||||||
|
mode: 'inline',
|
||||||
|
clearable: true,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/periods?order=name',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: payload.data.items.map(item => {\r\n return {\r\n label: `${item.name}`,\r\n value: "eq.".concat(item.id)\r\n }\r\n })\r\n}',
|
||||||
|
},
|
||||||
|
checkAll: false,
|
||||||
|
size: 'md',
|
||||||
|
searchable: true,
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
labelClassName: '',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'group',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
name: 'location_id',
|
||||||
|
mode: 'inline',
|
||||||
|
label: '地点',
|
||||||
|
clearable: true,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/locations?organization_id=eq.$centre_id&order=name',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: payload.data.items.map(item => {\r\n return {\r\n label: item.name,\r\n value: "eq.".concat(item.id)\r\n }\r\n })\r\n}',
|
||||||
|
},
|
||||||
|
checkAll: false,
|
||||||
|
size: 'md',
|
||||||
|
searchable: true,
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
className: 'm-l-sm',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
name: 'teacher_id',
|
||||||
|
mode: 'inline',
|
||||||
|
className: 'm-l-sm',
|
||||||
|
label: '教师',
|
||||||
|
clearable: true,
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
size: 'md',
|
||||||
|
checkAll: false,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/users?role=eq.teacher&order=name',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: payload.data.items.map(item => {\r\n return {\r\n label: `${item.name}(${item.code})`,\r\n value: "eq.".concat(item.id)\r\n }\r\n })\r\n}',
|
||||||
|
},
|
||||||
|
searchable: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
mode: '',
|
||||||
|
subFormMode: '',
|
||||||
|
gap: '',
|
||||||
|
className: '',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'divider',
|
||||||
|
lineStyle: 'solid',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'crud',
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/user2projects?select=*,att_status_text:user2project_att_status_dict_fk(dictvalue),schedule_status_text:user2project_schedule_status_dict_fk(dictvalue),users_ex:users_ex!user2project_student_id_fkey!inner(*),schedule_stats!inner(*)&semester_id=eq.${currentSemester}&schedule_status=neq.canceled&users_ex.role=eq.student&users_ex.org_type=eq.class&schedule_stats.organization_id=eq.${centre_id}',
|
||||||
|
data: {
|
||||||
|
page: '${page}',
|
||||||
|
perPage: '${perPage}',
|
||||||
|
'&': '$$',
|
||||||
|
},
|
||||||
|
adaptor:
|
||||||
|
"let supportDateTimeFormat = typeof(Intl.DateTimeFormat) === 'function'\r\n\r\npayload.data.items.forEach(item => {\r\n item.schedule_stats.day = supportDateTimeFormat ? `${item.schedule_stats.date}(${new Intl.DateTimeFormat('zh-CN', { weekday: 'short'}).format(new Date(item.schedule_stats.date))})` : item.schedule_stats.date;\r\n})\r\n\r\nreturn {\r\n ...payload\r\n}",
|
||||||
|
requestAdaptor:
|
||||||
|
"if (api.body.project_id === '') {\r\n api.url = api.url.replace('&project_id=', '')\r\n}\r\n\r\nif (api.body.date === '') {\r\n api.url = api.url.replace('&date=', '')\r\n} else {\r\n let date_former = api.body.date && api.body.date.split(',')[0]\r\n let date_latter = api.body.date && api.body.date.split(',')[1]\r\n\r\n if (date_former === date_latter) {\r\n api.url = api.url.replace(\r\n '&date=' + date_former + '%2C' + date_latter,\r\n '&schedule_stats.date=eq.' + date_former\r\n )\r\n } else {\r\n api.url = api.url.replace(\r\n '&date=' + date_former + '%2C' + date_latter,\r\n '&schedule_stats.date=gte.' + date_former + '&schedule_stats.date=lte.' + date_latter\r\n )\r\n }\r\n}\r\n\r\nif (api.body.period_id === '') {\r\n api.url = api.url.replace('&period_id=', '')\r\n} else {\r\n api.url = api.url.replace(\r\n '&period_id=' + api.body.period_id,\r\n '&schedule_stats.period_id=' + api.body.period_id\r\n )\r\n}\r\n\r\nif (api.body.location_id === '') {\r\n api.url = api.url.replace('&location_id=', '')\r\n} else {\r\n api.url = api.url.replace(\r\n '&location_id=' + api.body.location_id,\r\n '&schedule_stats.location_id=' + api.body.location_id\r\n )\r\n}\r\n\r\nif (api.body.teacher_id === '') {\r\n api.url = api.url.replace('&teacher_id=', '')\r\n} else {\r\n api.url = api.url.replace(\r\n '&teacher_id=' + api.body.teacher_id,\r\n '&schedule_stats.teacher_id=' + api.body.teacher_id\r\n )\r\n}\r\n\r\nreturn api;",
|
||||||
|
},
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'schedule_stats.project_name',
|
||||||
|
label: '项目',
|
||||||
|
type: 'text',
|
||||||
|
placeholder: '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'schedule_stats.day',
|
||||||
|
label: '日期',
|
||||||
|
type: 'text',
|
||||||
|
placeholder: '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '节次',
|
||||||
|
name: 'schedule_stats.period_name',
|
||||||
|
placeholder: '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '地点',
|
||||||
|
name: 'schedule_stats.location_name',
|
||||||
|
placeholder: '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '教师',
|
||||||
|
name: 'schedule_stats.teacher_name',
|
||||||
|
placeholder: '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '学号',
|
||||||
|
name: 'users_ex.code',
|
||||||
|
placeholder: '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '姓名',
|
||||||
|
name: 'users_ex.name',
|
||||||
|
placeholder: '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '班级',
|
||||||
|
name: 'users_ex.org_name',
|
||||||
|
placeholder: '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '选课状态',
|
||||||
|
name: 'schedule_status_text.dictvalue',
|
||||||
|
placeholder: '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '考勤状态',
|
||||||
|
name: 'att_status_text.dictvalue',
|
||||||
|
placeholder: '-',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
messages: {},
|
||||||
|
syncLocation: false,
|
||||||
|
pageField: 'page',
|
||||||
|
perPageField: 'perPage',
|
||||||
|
headerToolbar: [
|
||||||
|
{
|
||||||
|
type: 'export-excel',
|
||||||
|
align: 'right',
|
||||||
|
label: '导出',
|
||||||
|
icon: 'fa fa-download',
|
||||||
|
level: 'primary',
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/user2projects?select=*,att_status_text:user2project_att_status_dict_fk(dictvalue),schedule_status_text:user2project_schedule_status_dict_fk(dictvalue),users_ex:users_ex!user2project_student_id_fkey!inner(*),schedule_stats!inner(*)&semester_id=eq.${currentSemester}&schedule_status=neq.canceled&users_ex.role=eq.student&users_ex.org_type=eq.class&schedule_stats.organization_id=eq.${centre_id}',
|
||||||
|
data: {
|
||||||
|
project_id: '$project_id',
|
||||||
|
date: '$date',
|
||||||
|
period_id: '$period_id',
|
||||||
|
location_id: '$location_id',
|
||||||
|
teacher_id: '$teacher_id',
|
||||||
|
},
|
||||||
|
requestAdaptor:
|
||||||
|
"if (api.body.project_id === '') {\r\n api.url = api.url.replace('&project_id=', '')\r\n}\r\n\r\nif (api.body.date === '') {\r\n api.url = api.url.replace('&date=', '')\r\n} else {\r\n let date_former = api.body.date && api.body.date.split(',')[0]\r\n let date_latter = api.body.date && api.body.date.split(',')[1]\r\n\r\n if (date_former === date_latter) {\r\n api.url = api.url.replace(\r\n '&date=' + date_former + '%2C' + date_latter,\r\n '&schedule_stats.date=eq.' + date_former\r\n )\r\n } else {\r\n api.url = api.url.replace(\r\n '&date=' + date_former + '%2C' + date_latter,\r\n '&schedule_stats.date=gte.' + date_former + '&schedule_stats.date=lte.' + date_latter\r\n )\r\n }\r\n}\r\n\r\nif (api.body.period_id === '') {\r\n api.url = api.url.replace('&period_id=', '')\r\n} else {\r\n api.url = api.url.replace(\r\n '&period_id=' + api.body.period_id,\r\n '&schedule_stats.period_id=' + api.body.period_id\r\n )\r\n}\r\n\r\nif (api.body.location_id === '') {\r\n api.url = api.url.replace('&location_id=', '')\r\n} else {\r\n api.url = api.url.replace(\r\n '&location_id=' + api.body.location_id,\r\n '&schedule_stats.location_id=' + api.body.location_id\r\n )\r\n}\r\n\r\nif (api.body.teacher_id === '') {\r\n api.url = api.url.replace('&teacher_id=', '')\r\n} else {\r\n api.url = api.url.replace(\r\n '&teacher_id=' + api.body.teacher_id,\r\n '&schedule_stats.teacher_id=' + api.body.teacher_id\r\n )\r\n}\r\n\r\nreturn api;",
|
||||||
|
},
|
||||||
|
exportColumns: [
|
||||||
|
{
|
||||||
|
label: '项目',
|
||||||
|
name: 'schedule_stats.project_name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'schedule_stats.date',
|
||||||
|
label: '日期',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'schedule_stats.period_name',
|
||||||
|
label: '节次',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'schedule_stats.location_name',
|
||||||
|
label: '地点',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'schedule_stats.teacher_name',
|
||||||
|
label: '教师',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'users_ex.code',
|
||||||
|
label: '学号',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'users_ex.name',
|
||||||
|
label: '姓名',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'users_ex.org_name',
|
||||||
|
label: '班级',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'schedule_status_text.dictvalue',
|
||||||
|
label: '选课状态',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'att_status_text.dictvalue',
|
||||||
|
label: '考勤状态',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
filename: '选课名单',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
footerToolbar: [
|
||||||
|
{ type: 'pagination' },
|
||||||
|
{ type: 'switch-per-page' },
|
||||||
|
{ type: 'statistics' },
|
||||||
|
],
|
||||||
|
name: 'manage_list',
|
||||||
|
perPageAvailable: [10, 20, 30, 40, 50],
|
||||||
|
placeholder: '-',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
title: '',
|
||||||
|
messages: {},
|
||||||
|
bodyClassName: '',
|
||||||
|
className: '',
|
||||||
|
headerClassName: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
export { schema };
|
||||||
332
src/pages/schema/centre/schedule/location_settings.schema.ts
Normal file
332
src/pages/schema/centre/schedule/location_settings.schema.ts
Normal file
@@ -0,0 +1,332 @@
|
|||||||
|
const schema = {
|
||||||
|
type: 'page',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
className: '',
|
||||||
|
submitOnChange: true,
|
||||||
|
reload: 'loc_set?locationSelect=$locationSelect',
|
||||||
|
wrapWithPanel: false,
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
name: 'locationSelect',
|
||||||
|
label: '查询',
|
||||||
|
mode: 'inline',
|
||||||
|
size: 'md',
|
||||||
|
clearable: true,
|
||||||
|
searchable: true,
|
||||||
|
source: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/locations?organization_id=eq.$centre_id&order=code',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: {\r\n ...payload.data,\r\n items: payload.data.items.map(item => {\r\n return {\r\n label: item.name,\r\n value: item.id\r\n }\r\n })\r\n }\r\n}',
|
||||||
|
},
|
||||||
|
inputClassName: 'm-l-xs',
|
||||||
|
checkAll: false,
|
||||||
|
perPageAvailable: [10],
|
||||||
|
options: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ type: 'divider', lineStyle: 'solid' },
|
||||||
|
{
|
||||||
|
type: 'tpl',
|
||||||
|
className: 'm-b-sm',
|
||||||
|
tpl: '<% if (data.excludeRoomTime) { %>\n <span class="label label-warning">选择不可用时间<span>\n<% } else { %>\n <span class="label label-info">选择可用时间<span>\n<% } %>',
|
||||||
|
inline: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'crud',
|
||||||
|
syncLocation: false,
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/locations?organization_id=eq.$centre_id&order=code',
|
||||||
|
data: { page: '$page', perPage: '$perPage', id: 'eq.$locationSelect' },
|
||||||
|
requestAdaptor:
|
||||||
|
"if (api.query.id === 'eq.') {\r\n api.url = api.url.replace('&id=eq.', '')\r\n}\r\n\r\nreturn {\r\n ...api\r\n}",
|
||||||
|
adaptor: '',
|
||||||
|
replaceData: false,
|
||||||
|
},
|
||||||
|
perPageAvailable: [20, 40, 80],
|
||||||
|
messages: {},
|
||||||
|
name: 'loc_set',
|
||||||
|
defaultParams: { perPage: 20 },
|
||||||
|
card: {
|
||||||
|
type: 'card',
|
||||||
|
header: { title: '$name', subTitle: '$code' },
|
||||||
|
body: [{ type: 'tpl', tpl: '${intro|raw}' }],
|
||||||
|
toolbar: [
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '时间选择',
|
||||||
|
icon: 'fa fa-group',
|
||||||
|
iconClassName: '',
|
||||||
|
reload: '',
|
||||||
|
id: 'u:f67c49dcfe29',
|
||||||
|
editorState: 'default',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'timeslot-renderer',
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/timeslots?select=id,date,organization_id,location_id,periods(id,start_time,end_time)&location_id=eq.${id}&organization_id=eq.${centre_id}',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n data: {\r\n timeslots: payload.data.items.map(item => {\r\n return {\r\n id: item.id,\r\n date: item.date,\r\n semester_id: item.semester_id,\r\n organization_id: item.organization_id,\r\n location_id: item.location_id,\r\n period: item.periods\r\n }\r\n })\r\n }\r\n}',
|
||||||
|
},
|
||||||
|
copy: {
|
||||||
|
type: 'button',
|
||||||
|
label: '按钮',
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
title: '复制本周设置到其他周',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
title: '表单',
|
||||||
|
controls: [
|
||||||
|
{
|
||||||
|
type: 'timeslot-copy',
|
||||||
|
name: 'timeslotcopy',
|
||||||
|
mode: 'normal',
|
||||||
|
target: 'location',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
api: {
|
||||||
|
method: 'post',
|
||||||
|
url: 'rest/rpc/timeslots',
|
||||||
|
dataType: 'json',
|
||||||
|
headers: { Prefer: 'params=single-object' },
|
||||||
|
requestAdaptor:
|
||||||
|
'return {\r\n ...api,\r\n data: api.data.timeslotcopy\r\n}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: 'dialog',
|
||||||
|
closeOnEsc: false,
|
||||||
|
showCloseButton: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
target: 'location',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
title: '场地时间设置',
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
size: 'md',
|
||||||
|
actions: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '预览',
|
||||||
|
icon: 'fa fa-eye',
|
||||||
|
level: 'link',
|
||||||
|
size: 'md',
|
||||||
|
iconClassName: '',
|
||||||
|
visibleOn: '!this.excludeRoomTime',
|
||||||
|
id: 'u:c8b5eb1749e3',
|
||||||
|
editorState: 'default',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '场地可用时间',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'tpl',
|
||||||
|
tpl: '<span class="label" style="background: #e5e7eb;">X</span>\n<span style="vertical-align: middle;">不可用时间</span>\n<span class="label label-info">X</span>\n<span style="vertical-align: middle;">可用时间</span>',
|
||||||
|
inline: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'crud',
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/periods?select=*,timeslots(*)×lots.organization_id=eq.$centre_id×lots.date=gte.${semester.since}×lots.date=lte.${semester.to}×lots.location_id=eq.$id&order=code',
|
||||||
|
adaptor:
|
||||||
|
"let items = []\r\nconst week_list = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']\r\nconst oneday = 24 * 60 * 60 * 1000\r\nconst get_week_num = (start, end) => {\r\n let s = new Date(start)\r\n let s_ms = s.getTime()\r\n let s_day = s.getDay() ? s.getDay() : 7\r\n s.setTime(s_ms - (s_day - 1) * oneday)\r\n s_ms = s.getTime()\r\n let e = new Date(end)\r\n let e_ms = e.getTime()\r\n let e_day = e.getDay() ? e.getDay() : 7\r\n return {\r\n sem_start: s,\r\n day: e_day,\r\n week_num: Math.ceil(((e_ms - s_ms) / oneday + 1) / 7)\r\n }\r\n}\r\nlet start = /(?<=\\[date\\]\\[0\\]=gte\\.)\\d+-\\d+-\\d+/g.exec(api.url)[0]\r\nlet end = /(?<=\\[date\\]\\[1\\]=lte\\.)\\d+-\\d+-\\d+/g.exec(api.url)[0]\r\nconst { sem_start, week_num } = get_week_num(start, end)\r\nfor (let i = 0; i < 7; i++) {\r\n let date_temp = new Date(sem_start)\r\n let date_temp_ms = date_temp.getTime()\r\n payload.data.items.map(x => {\r\n const [h, m, s] = x.start_time.split(':')\r\n return {\r\n ...x,\r\n cmp_time: new Date(2020, 0, 1, h, m, s)\r\n }\r\n }).sort((a, b) => {\r\n return a.cmp_time - b.cmp_time\r\n }).forEach(item => {\r\n let week_num_list = []\r\n for (let j = 0; j < week_num; j++) {\r\n date_temp.setTime(date_temp_ms + j * 7 * oneday + i * oneday)\r\n week_num_list.push({\r\n week: j + 1,\r\n date: null,\r\n tpl: \"<span title='\".concat(date_temp.toISOString().split('T')[0], \"' class='label' style='background: #e5e7eb;'>\", j + 1, \"</span>\")\r\n })\r\n }\r\n items.push({\r\n day: {\r\n lab: week_list[i],\r\n val: i + 1\r\n },\r\n period: {\r\n lab: item.name,\r\n val: item.id\r\n },\r\n weeks: week_num_list\r\n })\r\n })\r\n}\r\nconst row_mem = payload.data.items.length\r\npayload.data.items.map(x => {\r\n const [h, m, s] = x.start_time.split(':')\r\n return {\r\n ...x,\r\n cmp_time: new Date(2020, 0, 1, h, m, s)\r\n }\r\n}).sort((a, b) => {\r\n return a.cmp_time - b.cmp_time\r\n}).forEach((item, index) => {\r\n item.timeslots && item.timeslots.forEach(i => {\r\n const { day, week_num } = get_week_num(sem_start, i.date)\r\n items[(day - 1) * row_mem + index].weeks[week_num - 1].date = i.date\r\n items[(day - 1) * row_mem + index].weeks[week_num - 1].id = i.id\r\n const week = items[(day - 1) * row_mem + index].weeks[week_num - 1].week\r\n items[(day - 1) * row_mem + index].weeks[week_num - 1].tpl = \"<span title='\".concat(i.date, \"' class='label label-primary'>\", week, \"</span>\")\r\n })\r\n})\r\nreturn {\r\n ...payload,\r\n data: {\r\n items: items\r\n }\r\n}\r\n",
|
||||||
|
requestAdaptor: '',
|
||||||
|
},
|
||||||
|
messages: {},
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'day.lab',
|
||||||
|
label: '',
|
||||||
|
type: 'text',
|
||||||
|
inline: true,
|
||||||
|
className: 'common-padding',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '',
|
||||||
|
name: 'period.lab',
|
||||||
|
placeholder: '-',
|
||||||
|
className: 'common-padding',
|
||||||
|
inline: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'weeks',
|
||||||
|
label: '',
|
||||||
|
type: 'each',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
type: 'tpl',
|
||||||
|
tpl: '<%= data.tpl %>',
|
||||||
|
inline: true,
|
||||||
|
className: 'm-r-xs',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
placeholder: '-',
|
||||||
|
className: 'common-padding',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
combineNum: 1,
|
||||||
|
columnsTogglable: false,
|
||||||
|
syncLocation: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
size: 'lg',
|
||||||
|
data: null,
|
||||||
|
bodyClassName: 'p-t-none',
|
||||||
|
actions: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
label: '预览',
|
||||||
|
icon: 'fa fa-eye',
|
||||||
|
level: 'link',
|
||||||
|
size: 'md',
|
||||||
|
iconClassName: '',
|
||||||
|
visibleOn: 'this.excludeRoomTime',
|
||||||
|
id: 'u:fb5fb80671b4',
|
||||||
|
editorState: 'default',
|
||||||
|
onEvent: {
|
||||||
|
click: {
|
||||||
|
weight: 0,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
ignoreError: false,
|
||||||
|
actionType: 'dialog',
|
||||||
|
dialog: {
|
||||||
|
type: 'dialog',
|
||||||
|
title: '场地可用时间',
|
||||||
|
body: [
|
||||||
|
{
|
||||||
|
type: 'tpl',
|
||||||
|
tpl: '<span class="label" style="background: #e5e7eb;">X</span>\n<span style="vertical-align: middle;">不可用时间</span>\n<span class="label label-info">X</span>\n<span style="vertical-align: middle;">可用时间</span>',
|
||||||
|
inline: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'crud',
|
||||||
|
api: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/periods?select=*,timeslots(*)×lots.organization_id=eq.$centre_id×lots.date=gte.${semester.since}×lots.date=lte.${semester.to}×lots.location_id=eq.$id&order=code',
|
||||||
|
adaptor:
|
||||||
|
"let items = []\r\nconst week_list = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']\r\nconst oneday = 24 * 60 * 60 * 1000\r\nconst get_week_num = (start, end) => {\r\n let s = new Date(start)\r\n let s_ms = s.getTime()\r\n let s_day = s.getDay() ? s.getDay() : 7\r\n s.setTime(s_ms - (s_day - 1) * oneday)\r\n s_ms = s.getTime()\r\n let e = new Date(end)\r\n let e_ms = e.getTime()\r\n let e_day = e.getDay() ? e.getDay() : 7\r\n return {\r\n sem_start: s,\r\n day: e_day,\r\n week_num: Math.ceil(((e_ms - s_ms) / oneday + 1) / 7)\r\n }\r\n}\r\nlet start = /(?<=\\[date\\]\\[0\\]=gte\\.)\\d+-\\d+-\\d+/g.exec(api.url)[0]\r\nlet end = /(?<=\\[date\\]\\[1\\]=lte\\.)\\d+-\\d+-\\d+/g.exec(api.url)[0]\r\nconst { sem_start, week_num } = get_week_num(start, end)\r\nfor (let i = 0; i < 7; i++) {\r\n let date_temp = new Date(sem_start)\r\n let date_temp_ms = date_temp.getTime()\r\n payload.data.items.map(x => {\r\n const [h, m, s] = x.start_time.split(':')\r\n return {\r\n ...x,\r\n cmp_time: new Date(2020, 0, 1, h, m, s)\r\n }\r\n }).sort((a, b) => {\r\n return a.cmp_time - b.cmp_time\r\n }).forEach(item => {\r\n let week_num_list = []\r\n for (let j = 0; j < week_num; j++) {\r\n date_temp.setTime(date_temp_ms + j * 7 * oneday + i * oneday)\r\n week_num_list.push({\r\n week: j + 1,\r\n date: null,\r\n tpl: \"<span title='\".concat(date_temp.toISOString().split('T')[0], \"' class='label label-info'>\", j + 1, \"</span>\")\r\n })\r\n }\r\n items.push({\r\n day: {\r\n lab: week_list[i],\r\n val: i + 1\r\n },\r\n period: {\r\n lab: item.name,\r\n val: item.id\r\n },\r\n weeks: week_num_list\r\n })\r\n })\r\n}\r\nconst row_mem = payload.data.items.length\r\npayload.data.items.map(x => {\r\n const [h, m, s] = x.start_time.split(':')\r\n return {\r\n ...x,\r\n cmp_time: new Date(2020, 0, 1, h, m, s)\r\n }\r\n}).sort((a, b) => {\r\n return a.cmp_time - b.cmp_time\r\n}).forEach((item, index) => {\r\n item.timeslots && item.timeslots.forEach(i => {\r\n const { day, week_num } = get_week_num(sem_start, i.date)\r\n items[(day - 1) * row_mem + index].weeks[week_num - 1].date = i.date\r\n items[(day - 1) * row_mem + index].weeks[week_num - 1].id = i.id\r\n const week = items[(day - 1) * row_mem + index].weeks[week_num - 1].week\r\n items[(day - 1) * row_mem + index].weeks[week_num - 1].tpl = \"<span class='label' style='background: #e5e7eb;'>\".concat(week, \"</span>\")\r\n items[(day - 1) * row_mem + index].weeks[week_num - 1].tpl = \"<span title='\".concat(i.date, \"' class='label' style='background: #e5e7eb;'>\", week, \"</span>\")\r\n })\r\n})\r\nreturn {\r\n ...payload,\r\n data: {\r\n items: items\r\n }\r\n}",
|
||||||
|
requestAdaptor: '',
|
||||||
|
},
|
||||||
|
messages: {},
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'day.lab',
|
||||||
|
label: '',
|
||||||
|
type: 'text',
|
||||||
|
inline: true,
|
||||||
|
className: 'common-padding',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
label: '',
|
||||||
|
name: 'period.lab',
|
||||||
|
placeholder: '-',
|
||||||
|
className: 'common-padding',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'weeks',
|
||||||
|
label: '',
|
||||||
|
type: 'each',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
type: 'tpl',
|
||||||
|
tpl: '<%= data.tpl %>',
|
||||||
|
inline: true,
|
||||||
|
className: 'm-r-xs',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
placeholder: '-',
|
||||||
|
className: 'common-padding',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
combineNum: 1,
|
||||||
|
columnsTogglable: false,
|
||||||
|
syncLocation: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closeOnEsc: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
size: 'lg',
|
||||||
|
data: null,
|
||||||
|
bodyClassName: 'p-t-none',
|
||||||
|
actions: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
actionsCount: 3,
|
||||||
|
},
|
||||||
|
mode: 'cards',
|
||||||
|
headerToolbar: [],
|
||||||
|
footerToolbar: [
|
||||||
|
{ type: 'pagination' },
|
||||||
|
{ type: 'switch-per-page' },
|
||||||
|
{ type: 'statistics' },
|
||||||
|
],
|
||||||
|
columnsCount: 4,
|
||||||
|
placeholder: '暂无数据',
|
||||||
|
pageField: 'page',
|
||||||
|
perPageField: 'perPage',
|
||||||
|
initApi: '',
|
||||||
|
initFetch: '',
|
||||||
|
checkAll: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
messages: {},
|
||||||
|
initApi: {
|
||||||
|
method: 'get',
|
||||||
|
url: 'rest/config?key=eq.system&organization_id=eq.${centre_id}',
|
||||||
|
adaptor:
|
||||||
|
'return {\r\n ...payload,\r\n data: {\r\n excludeRoomTime: payload.data.items[0].value.excludeRoomTime\r\n }\r\n}',
|
||||||
|
},
|
||||||
|
title: '',
|
||||||
|
cssVars: { '--Checkbox-onDisabled-color': 'transparent' },
|
||||||
|
};
|
||||||
|
|
||||||
|
export { schema };
|
||||||
2143
src/pages/schema/centre/schedule/open.schema.ts
Normal file
2143
src/pages/schema/centre/schedule/open.schema.ts
Normal file
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user