提交 e1bcb53c 编写于 作者: yanshaowei's avatar yanshaowei

init

上级
流水线 #219 已失败 ,包含阶段
> 1%
last 2 versions
not ie <= 8
.DS_Store
node_modules
/dist
/tests/e2e/videos/
/tests/e2e/screenshots/
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw*
# VUE_R6
#### Description
{**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**}
#### Software Architecture
Software architecture description
#### Installation
1. xxxx
2. xxxx
3. xxxx
#### Instructions
1. xxxx
2. xxxx
3. xxxx
#### Contribution
1. Fork the repository
2. Create Feat_xxx branch
3. Commit your code
4. Create Pull Request
#### Gitee Feature
1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
4. The most valuable open source project [GVP](https://gitee.com/gvp)
5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
\ No newline at end of file
# app
## Project setup
```
yarn install
```
### Compiles and hot-reloads for development
```
yarn run serve
```
### Compiles and minifies for production
```
yarn run build
```
### Run your tests
```
yarn run test
```
### Lints and fixes files
```
yarn run lint
```
### Run your end-to-end tests
```
yarn run test:e2e
```
### Run your unit tests
```
yarn run test:unit
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).
## 更新日志
### 1.1.0.1
#### 新特性
- 默认错误显示页
- 添加默认错误显示页面(404、500)(by @JunZai)
### 1.1.0.0
*2019-08-08*
#### 非兼容性更新
- 应用
- 支持多首页模式(删除src下main.ts文件,将其挂在首页目录下;新增template.html;)(by @JunZai)
### 1.0.0.3
*2019-08-02*
#### 新特性
- 关系表格数据刷新
- 编辑页面标签模式打开刷新关联视图 [(by @zcdtk)]
- 文件和图片上传组件
- 上传时带srfappdata参数
#### 优化
- AppCheckBox、AppRadioGroup、DropDownList
- 代码表组件本地化缓存 [(#3769c67 by @zcdtk)](https://gitee.com/dev_ibizsys/VUE_R6/commit/3769c67d99370003949fac86dfbe7e1b5630a551)
- AppRichTextEditor
- 富文本编辑器功能补充 [(#87eecb1 by @zcdtk)](https://gitee.com/dev_ibizsys/VUE_R6/commit/87eecb1b26c6ce9c64d4c1b87baf87b73643661e)
#### Bug 修复
- DropDownList
- 下拉列表框值处理异常修复 [(#dc6f44e by @zcdtk)](https://gitee.com/dev_ibizsys/VUE_R6/commit/dc6f44e20e8c26eb5d66972b652f7704887cc2cf)
- InputBox
- 数值模式空格输入 [(#f52f9c4 by @zcdtk)](https://gitee.com/dev_ibizsys/VUE_R6/commit/f52f9c420698847a8aa9f67fcf01ce30ebd6715d)
### 1.0.0.2
*2019-07-19*
#### 新特性
- GridView
- 支持表格数据激活模式 (by @zcdtk)
- utils
- 工具方法添加序列号处理 (by @zcdtk)
#### Bug 修复
- AppModal、AppDrawer
- 模态与抽屉层级与多语言异常修复 [(#61f0210 by @zcdtk)](https://gitee.com/dev_ibizsys/VUE_R6/commit/61f0210336be4b6011ca2c1215812ac13cfb20aa)
- AppRichTextEditor
- 富文本编编辑器打包异常 [(#3df7de0 by @zcdtk)](https://gitee.com/dev_ibizsys/VUE_R6/commit/3df7de09543f7e732338397e478ed44a13184809)
### 1.0.0.1
*2019-06-13*
#### 新特性
- ToolBar
- 支持提示信息
- Form
- 分组标题栏关闭模式
### 1.0.0.0
*2019-06-26*
#### Bug 修复
- Grid
- 修复表格代码绘制(或模式) [af07ea](https://gitee.com/dev_ibizsys/VUE_R6/commit/af07eafb09a92d31dcbc141e702691e01c2e5807)
module.exports = {
presets: [
'@vue/app'
]
}
{
"pluginsFile": "tests/e2e/plugins/index.js"
}
module.exports = {
moduleFileExtensions: [
'js',
'jsx',
'json',
'vue',
'ts',
'tsx'
],
transform: {
'^.+\\.vue$': 'vue-jest',
'.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub',
'^.+\\.tsx?$': 'ts-jest'
},
transformIgnorePatterns: [
'/node_modules/'
],
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1'
},
snapshotSerializers: [
'jest-serializer-vue'
],
testMatch: [
'**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
],
testURL: 'http://localhost/',
globals: {
'ts-jest': {
babelConfig: true
}
}
}
{
"name": "app",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "node --max_old_space_size=8102 ./node_modules/@vue/cli-service/bin/vue-cli-service serve",
"build": "node --max_old_space_size=8102 ./node_modules/@vue/cli-service/bin/vue-cli-service build",
"lint": "vue-cli-service lint",
"test:e2e": "vue-cli-service test:e2e",
"test:unit": "vue-cli-service test:unit"
},
"dependencies": {
"axios": "^0.19.0",
"codemirror": "^5.48.2",
"core-js": "^2.6.5",
"css-element-queries": "^1.2.1",
"echarts": "^4.2.1",
"element-ui": "^2.11.1",
"font-awesome": "4.7.0",
"iview": "^3.4.2",
"rxjs": "^6.5.2",
"tinymce": "4.8.5",
"vue": "^2.6.10",
"vue-class-component": "^7.1.0",
"vue-i18n": "^8.12.0",
"vue-property-decorator": "^8.2.0",
"vue-router": "^3.0.7",
"vuex": "^3.1.1"
},
"devDependencies": {
"@types/codemirror": "0.0.74",
"@types/echarts": "^4.1.9",
"@types/jest": "^23.1.4",
"@vue/cli-plugin-babel": "^3.5.0",
"@vue/cli-plugin-e2e-cypress": "^3.5.0",
"@vue/cli-plugin-typescript": "^3.5.0",
"@vue/cli-plugin-unit-jest": "^3.5.0",
"@vue/cli-service": "^3.5.0",
"@vue/test-utils": "1.0.0-beta.29",
"babel-core": "7.0.0-bridge.0",
"less": "^3.0.4",
"less-loader": "^4.1.0",
"ts-jest": "^23.0.0",
"typescript": "^3.2.1",
"vue-template-compiler": "^2.6.10"
}
}
module.exports = {
plugins: {
autoprefixer: {}
}
}
tinymce.addI18n('en_GB',{
"Cut": "Cut",
"Heading 5": "Heading 5",
"Header 2": "Header 2",
"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.",
"Heading 4": "Heading 4",
"Div": "Div",
"Heading 2": "Heading 2",
"Paste": "Paste",
"Close": "Close",
"Font Family": "Font Family",
"Pre": "Pre",
"Align right": "Align right",
"New document": "New document",
"Blockquote": "Blockquote",
"Numbered list": "Numbered list",
"Heading 1": "Heading 1",
"Headings": "Headings",
"Increase indent": "Increase indent",
"Formats": "Formats",
"Headers": "Headers",
"Select all": "Select all",
"Header 3": "Header 3",
"Blocks": "Blocks",
"Undo": "Undo",
"Strikethrough": "Strike-through",
"Bullet list": "Bullet list",
"Header 1": "Header 1",
"Superscript": "Superscript",
"Clear formatting": "Clear formatting",
"Font Sizes": "Font Sizes",
"Subscript": "Subscript",
"Header 6": "Header 6",
"Redo": "Redo",
"Paragraph": "Paragraph",
"Ok": "Ok",
"Bold": "Bold",
"Code": "Code",
"Italic": "Italic",
"Align center": "Align centre",
"Header 5": "Header 5",
"Heading 6": "Heading 6",
"Heading 3": "Heading 3",
"Decrease indent": "Decrease indent",
"Header 4": "Header 4",
"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.",
"Underline": "Underline",
"Cancel": "Cancel",
"Justify": "Justify",
"Inline": "Inline",
"Copy": "Copy",
"Align left": "Align left",
"Visual aids": "Visual aids",
"Lower Greek": "Lower Greek",
"Square": "Square",
"Default": "Default",
"Lower Alpha": "Lower Alpha",
"Circle": "Circle",
"Disc": "Disc",
"Upper Alpha": "Upper Alpha",
"Upper Roman": "Upper Roman",
"Lower Roman": "Lower Roman",
"Id should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.": "ID should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.",
"Name": "Name",
"Anchor": "Anchor",
"Id": "ID",
"You have unsaved changes are you sure you want to navigate away?": "You have unsaved changes are you sure you want to navigate away?",
"Restore last draft": "Restore last draft",
"Special character": "Special character",
"Source code": "Source code",
"Language": "Language",
"Insert\/Edit code sample": "Insert\/Edit code sample",
"B": "B",
"R": "R",
"G": "G",
"Color": "Colour",
"Right to left": "Right to left",
"Left to right": "Left to right",
"Emoticons": "Emoticons",
"Robots": "Robots",
"Document properties": "Document properties",
"Title": "Title",
"Keywords": "Keywords",
"Encoding": "Encoding",
"Description": "Description",
"Author": "Author",
"Fullscreen": "Full-screen",
"Horizontal line": "Horizontal line",
"Horizontal space": "Horizontal space",
"Insert\/edit image": "Insert\/edit image",
"General": "General",
"Advanced": "Advanced",
"Source": "Source",
"Border": "Border",
"Constrain proportions": "Constrain proportions",
"Vertical space": "Vertical space",
"Image description": "Image description",
"Style": "Style",
"Dimensions": "Dimensions",
"Insert image": "Insert image",
"Image": "Image",
"Zoom in": "Zoom in",
"Contrast": "Contrast",
"Back": "Back",
"Gamma": "Gamma",
"Flip horizontally": "Flip horizontally",
"Resize": "Resize",
"Sharpen": "Sharpen",
"Zoom out": "Zoom out",
"Image options": "Image options",
"Apply": "Apply",
"Brightness": "Brightness",
"Rotate clockwise": "Rotate clockwise",
"Rotate counterclockwise": "Rotate counterclockwise",
"Edit image": "Edit image",
"Color levels": "Colour levels",
"Crop": "Crop",
"Orientation": "Orientation",
"Flip vertically": "Flip vertically",
"Invert": "Invert",
"Date\/time": "Date\/time",
"Insert date\/time": "Insert date\/time",
"Remove link": "Remove link",
"Url": "URL",
"Text to display": "Text to display",
"Anchors": "Anchors",
"Insert link": "Insert link",
"Link": "Link",
"New window": "New window",
"None": "None",
"The URL you entered seems to be an external link. Do you want to add the required http:\/\/ prefix?": "The URL you entered seems to be an external link. Do you want to add the required http:\/\/ prefix?",
"Paste or type a link": "Paste or type a link",
"Target": "Target",
"The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?": "The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?",
"Insert\/edit link": "Insert\/edit link",
"Insert\/edit video": "Insert\/edit video",
"Media": "Media",
"Alternative source": "Alternative source",
"Paste your embed code below:": "Paste your embed code below:",
"Insert video": "Insert video",
"Poster": "Poster",
"Insert\/edit media": "Insert\/edit media",
"Embed": "Embed",
"Nonbreaking space": "Non-breaking space",
"Page break": "Page break",
"Paste as text": "Paste as text",
"Preview": "Preview",
"Print": "Print",
"Save": "Save",
"Could not find the specified string.": "Could not find the specified string.",
"Replace": "Replace",
"Next": "Next",
"Whole words": "Whole words",
"Find and replace": "Find and replace",
"Replace with": "Replace with",
"Find": "Find",
"Replace all": "Replace all",
"Match case": "Match case",
"Prev": "Prev",
"Spellcheck": "Spell-check",
"Finish": "Finish",
"Ignore all": "Ignore all",
"Ignore": "Ignore",
"Add to Dictionary": "Add to Dictionary",
"Insert row before": "Insert row before",
"Rows": "Rows",
"Height": "Height",
"Paste row after": "Paste row after",
"Alignment": "Alignment",
"Border color": "Border colour",
"Column group": "Column group",
"Row": "Row",
"Insert column before": "Insert column before",
"Split cell": "Split cell",
"Cell padding": "Cell padding",
"Cell spacing": "Cell spacing",
"Row type": "Row type",
"Insert table": "Insert table",
"Body": "Body",
"Caption": "Caption",
"Footer": "Footer",
"Delete row": "Delete row",
"Paste row before": "Paste row before",
"Scope": "Scope",
"Delete table": "Delete table",
"H Align": "H Align",
"Top": "Top",
"Header cell": "Header cell",
"Column": "Column",
"Row group": "Row group",
"Cell": "Cell",
"Middle": "Middle",
"Cell type": "Cell type",
"Copy row": "Copy row",
"Row properties": "Row properties",
"Table properties": "Table properties",
"Bottom": "Bottom",
"V Align": "V Align",
"Header": "Header",
"Right": "Right",
"Insert column after": "Insert column after",
"Cols": "Cols",
"Insert row after": "Insert row after",
"Width": "Width",
"Cell properties": "Cell properties",
"Left": "Left",
"Cut row": "Cut row",
"Delete column": "Delete column",
"Center": "Centre",
"Merge cells": "Merge cells",
"Insert template": "Insert template",
"Templates": "Templates",
"Background color": "Background colour",
"Custom...": "Custom...",
"Custom color": "Custom colour",
"No color": "No colour",
"Text color": "Text colour",
"Table of Contents": "Table of Contents",
"Show blocks": "Show blocks",
"Show invisible characters": "Show invisible characters",
"Words: {0}": "Words: {0}",
"Insert": "Insert",
"File": "File",
"Edit": "Edit",
"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help",
"Tools": "Tools",
"View": "View",
"Table": "Table",
"Format": "Format"
});
\ No newline at end of file
此差异已折叠。
/* PrismJS 1.14.0
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
/**
* prism.js default theme for JavaScript, CSS and HTML
* Based on dabblet (http://dabblet.com)
* @author Lea Verou
*/
code[class*="language-"],
pre[class*="language-"] {
color: black;
background: none;
text-shadow: 0 1px white;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection {
text-shadow: none;
background: #b3d4fc;
}
pre[class*="language-"]::selection, pre[class*="language-"] ::selection,
code[class*="language-"]::selection, code[class*="language-"] ::selection {
text-shadow: none;
background: #b3d4fc;
}
@media print {
code[class*="language-"],
pre[class*="language-"] {
text-shadow: none;
}
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
}
:not(pre) > code[class*="language-"],
pre[class*="language-"] {
background: #f5f2f0;
}
/* Inline code */
:not(pre) > code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #999;
}
.namespace {
opacity: .7;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #905;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #690;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #9a6e3a;
background: hsla(0, 0%, 100%, .5);
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: #07a;
}
.token.function,
.token.class-name {
color: #DD4A68;
}
.token.regex,
.token.important,
.token.variable {
color: #e90;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
.word-wrap{word-wrap:break-word;-ms-word-break:break-all;word-break:break-all;word-break:break-word;-ms-hyphens:auto;-moz-hyphens:auto;-webkit-hyphens:auto;hyphens:auto}.mce-content-body .mce-reset{margin:0;padding:0;border:0;outline:0;vertical-align:top;background:transparent;text-decoration:none;color:black;font-family:Arial;font-size:11px;text-shadow:none;float:none;position:static;width:auto;height:auto;white-space:nowrap;cursor:inherit;line-height:normal;font-weight:normal;text-align:left;-webkit-tap-highlight-color:transparent;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;direction:ltr;max-width:none}.mce-object{border:1px dotted #3A3A3A;background:#D5D5D5 url(img/object.gif) no-repeat center}.mce-preview-object{display:inline-block;position:relative;margin:0 2px 0 2px;line-height:0;border:1px solid gray}.mce-preview-object[data-mce-selected="2"] .mce-shim{display:none}.mce-preview-object .mce-shim{position:absolute;top:0;left:0;width:100%;height:100%;background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)}figure.align-left{float:left}figure.align-right{float:right}figure.image.align-center{display:table;margin-left:auto;margin-right:auto}figure.image{display:inline-block;border:1px solid gray;margin:0 2px 0 1px;background:#f5f2f0}figure.image img{margin:8px 8px 0 8px}figure.image figcaption{margin:6px 8px 6px 8px;text-align:center}.mce-toc{border:1px solid gray}.mce-toc h2{margin:4px}.mce-toc li{list-style-type:none}.mce-pagebreak{cursor:default;display:block;border:0;width:100%;height:5px;border:1px dashed #666;margin-top:15px;page-break-before:always}@media print{.mce-pagebreak{border:0}}.mce-item-anchor{cursor:default;display:inline-block;-webkit-user-select:all;-webkit-user-modify:read-only;-moz-user-select:all;-moz-user-modify:read-only;user-select:all;user-modify:read-only;width:9px !important;height:9px !important;border:1px dotted #3A3A3A;background:#D5D5D5 url(img/anchor.gif) no-repeat center}.mce-nbsp,.mce-shy{background:#AAA}.mce-shy::after{content:'-'}.mce-match-marker{background:#AAA;color:#fff}.mce-match-marker-selected{background:#3399ff;color:#fff}.mce-spellchecker-word{border-bottom:2px solid rgba(208,2,27,0.5);cursor:default}.mce-spellchecker-grammar{border-bottom:2px solid #008000;cursor:default}.mce-item-table,.mce-item-table td,.mce-item-table th,.mce-item-table caption{border:1px dashed #BBB}td[data-mce-selected],th[data-mce-selected]{background-color:#2276d2 !important}.mce-edit-focus{outline:1px dotted #333}.mce-content-body *[contentEditable=false] *[contentEditable=true]:focus{outline:2px solid #2276d2}.mce-content-body *[contentEditable=false] *[contentEditable=true]:hover{outline:2px solid #2276d2}.mce-content-body *[contentEditable=false][data-mce-selected]{outline:2px solid #2276d2}.mce-content-body.mce-content-readonly *[contentEditable=true]:focus,.mce-content-body.mce-content-readonly *[contentEditable=true]:hover{outline:none}.mce-content-body *[data-mce-selected="inline-boundary"]{background:#bfe6ff}.mce-content-body .mce-item-anchor[data-mce-selected]{background:#D5D5D5 url(img/anchor.gif) no-repeat center}.mce-content-body hr{cursor:default}.mce-content-body table{-webkit-nbsp-mode:normal}.ephox-snooker-resizer-bar{background-color:#2276d2;opacity:0}.ephox-snooker-resizer-cols{cursor:col-resize}.ephox-snooker-resizer-rows{cursor:row-resize}.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging{opacity:.2}.mce-content-body{line-height:1.3}
\ No newline at end of file
body{background-color:#FFFFFF;color:#000000;font-family:Verdana,Arial,Helvetica,sans-serif;font-size:14px;line-height:1.3;scrollbar-3dlight-color:#F0F0EE;scrollbar-arrow-color:#676662;scrollbar-base-color:#F0F0EE;scrollbar-darkshadow-color:#DDDDDD;scrollbar-face-color:#E0E0DD;scrollbar-highlight-color:#F0F0EE;scrollbar-shadow-color:#F0F0EE;scrollbar-track-color:#F5F5F5}td,th{font-family:Verdana,Arial,Helvetica,sans-serif;font-size:14px}.word-wrap{word-wrap:break-word;-ms-word-break:break-all;word-break:break-all;word-break:break-word;-ms-hyphens:auto;-moz-hyphens:auto;-webkit-hyphens:auto;hyphens:auto}.mce-content-body .mce-reset{margin:0;padding:0;border:0;outline:0;vertical-align:top;background:transparent;text-decoration:none;color:black;font-family:Arial;font-size:11px;text-shadow:none;float:none;position:static;width:auto;height:auto;white-space:nowrap;cursor:inherit;line-height:normal;font-weight:normal;text-align:left;-webkit-tap-highlight-color:transparent;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;direction:ltr;max-width:none}.mce-object{border:1px dotted #3A3A3A;background:#D5D5D5 url(img/object.gif) no-repeat center}.mce-preview-object{display:inline-block;position:relative;margin:0 2px 0 2px;line-height:0;border:1px solid gray}.mce-preview-object[data-mce-selected="2"] .mce-shim{display:none}.mce-preview-object .mce-shim{position:absolute;top:0;left:0;width:100%;height:100%;background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)}figure.align-left{float:left}figure.align-right{float:right}figure.image.align-center{display:table;margin-left:auto;margin-right:auto}figure.image{display:inline-block;border:1px solid gray;margin:0 2px 0 1px;background:#f5f2f0}figure.image img{margin:8px 8px 0 8px}figure.image figcaption{margin:6px 8px 6px 8px;text-align:center}.mce-toc{border:1px solid gray}.mce-toc h2{margin:4px}.mce-toc li{list-style-type:none}.mce-pagebreak{cursor:default;display:block;border:0;width:100%;height:5px;border:1px dashed #666;margin-top:15px;page-break-before:always}@media print{.mce-pagebreak{border:0}}.mce-item-anchor{cursor:default;display:inline-block;-webkit-user-select:all;-webkit-user-modify:read-only;-moz-user-select:all;-moz-user-modify:read-only;user-select:all;user-modify:read-only;width:9px !important;height:9px !important;border:1px dotted #3A3A3A;background:#D5D5D5 url(img/anchor.gif) no-repeat center}.mce-nbsp,.mce-shy{background:#AAA}.mce-shy::after{content:'-'}.mce-match-marker{background:#AAA;color:#fff}.mce-match-marker-selected{background:#3399ff;color:#fff}.mce-spellchecker-word{border-bottom:2px solid rgba(208,2,27,0.5);cursor:default}.mce-spellchecker-grammar{border-bottom:2px solid #008000;cursor:default}.mce-item-table,.mce-item-table td,.mce-item-table th,.mce-item-table caption{border:1px dashed #BBB}td[data-mce-selected],th[data-mce-selected]{background-color:#2276d2 !important}.mce-edit-focus{outline:1px dotted #333}.mce-content-body *[contentEditable=false] *[contentEditable=true]:focus{outline:2px solid #2276d2}.mce-content-body *[contentEditable=false] *[contentEditable=true]:hover{outline:2px solid #2276d2}.mce-content-body *[contentEditable=false][data-mce-selected]{outline:2px solid #2276d2}.mce-content-body.mce-content-readonly *[contentEditable=true]:focus,.mce-content-body.mce-content-readonly *[contentEditable=true]:hover{outline:none}.mce-content-body *[data-mce-selected="inline-boundary"]{background:#bfe6ff}.mce-content-body .mce-item-anchor[data-mce-selected]{background:#D5D5D5 url(img/anchor.gif) no-repeat center}.mce-content-body hr{cursor:default}.mce-content-body table{-webkit-nbsp-mode:normal}.ephox-snooker-resizer-bar{background-color:#2276d2;opacity:0}.ephox-snooker-resizer-cols{cursor:col-resize}.ephox-snooker-resizer-rows{cursor:row-resize}.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging{opacity:.2}
\ No newline at end of file
.tinymce-mobile-unfocused-selections .tinymce-mobile-unfocused-selection{position:absolute;display:inline-block;background-color:green;opacity:.5}body{-webkit-text-size-adjust:none}body img{max-width:96vw}body table img{max-width:95%}
\ No newline at end of file
此差异已折叠。
此差异已折叠。
import { Vue, Component } from 'vue-property-decorator';
@Component({})
export default class App extends Vue {
/**
* vue 生命周期
*
* @memberof App
*/
public mounted() {
document.body.setAttribute('vue-version', Vue.version);
}
/**
* 绘制内容
*
* @returns
* @memberof App
*/
public render() {
return <router-view/>;
}
}
\ No newline at end of file
import { Util } from './utils/util/util';
import { Http } from './utils/http/http';
import { CodeList } from './utils/code-list/code-list';
import { AppPopover } from './utils/app-popover/app-popover';
import { AppModal } from './utils/app-modal/app-modal';
import { AppDrawer } from './utils/app-drawer/app-drawer';
export const AppComponents = {
install(v: any, opt: any) {
v.prototype.$appdrawer = AppDrawer.getInstance();
v.prototype.$appmodal = AppModal.getInstance();
v.prototype.$apppopover = AppPopover.getInstance();
v.prototype.$codelist = CodeList.getInstance();
v.prototype.$http = Http.getInstance();
v.prototype.$util = Util;
v.component('app-tree', () => import('./components/app-tree/app-tree'));
v.component('app-keep-alive', () => import('./components/app-keep-alive/app-keep-alive.vue'));
v.component('tab-page-exp', () => import('./components/tab-page-exp/tab-page-exp.vue'));
v.component('app-form', () => import('./components/app-form/app-form'));
v.component('app-form-item', () => import('./components/app-form-item/app-form-item'));
v.component('app-form-item2', () => import('./components/app-form-item2/app-form-item2'));
v.component('app-form-group', () => import('./components/app-form-group/app-form-group'));
v.component('app-form-group2', () => import('./components/app-form-group2/app-form-group2'));
v.component('app-autocomplete', () => import('./components/app-autocomplete/app-autocomplete'));
v.component('app-picker', () => import('./components/app-picker/app-picker'));
v.component('app-mpicker', () => import('./components/app-mpicker/app-mpicker'));
v.component('app-form-druipart', () => import('./components/app-form-druipart/app-form-druipart'));
v.component('input-box', () => import('./components/input-box/input-box'));
v.component('dropdown-list', () => import('./components/dropdown-list/dropdown-list'));
v.component('upload-file', () => import('./components/upload-file/upload-file'));
v.component('app-theme', () => import('./components/app-theme/app-theme'));
v.component('app-user', () => import('./components/app-user/app-user'));
v.component('context-menu', () => import('./components/context-menu/context-menu'));
v.component('context-menu-container', () => import('./components/context-menu-container/context-menu-container'));
v.component('app-checkbox-list',() => import('./components/app-checkbox-list/app-checkbox-list'));
v.component('app-radio-group',() => import('./components/app-radio-group/app-radio-group'));
v.component('app-embed-picker', () => import('./components/app-embed-picker/app-embed-picker'));
v.component('app-rich-text-editor',() => import('./components/app-rich-text-editor/app-rich-text-editor'));
v.component('app-code-editor',() => import('./components/app-code-editor/app-code-editor'));
v.component('app-file-upload',() => import('./components/app-file-upload/app-file-upload'));
v.component('app-image-upload',() => import('./components/app-image-upload/app-image-upload'));
v.component('property-layout',() =>import('./components/property-layout/property-layout'));
v.component('app-range-editor',() =>import('./components/app-range-editor/app-range-editor'));
v.component('app-export-excel',() =>import('./components/app-export-excel/app-export-excel'));
v.component('app-lang',() =>import('./components/app-lang/app-lang'));
},
};
\ No newline at end of file
html, body {
height: 100%;
}
.app-error-view {
height: 100%;
width: 100%;
position: relative;
.app-error-container {
height: 380px;
width: 670px;
position: absolute;
top: calc((100% - 400px) / 2);
left: calc((100% - 670px) / 2);
display: flex;
align-items: center;
.error-text {
padding-left: 20px;
.error-text1 {
font-size: 20px;
margin-bottom: 20px;
}
.error-text2 {
font-size: 14px;
}
}
}
}
\ No newline at end of file
import { Vue, Component } from 'vue-property-decorator';
import './404.less';
@Component({})
export default class Error404 extends Vue {
/**
* 跳转首页
*
* @memberof Error404
*/
public gotoIndexView() {
this.$router.push('/');
}
/**
* 绘制内容
*
* @returns
* @memberof Error404
*/
public render() {
return (
<div class="app-error-view">
<div class="app-error-container">
<img src="/assets/img/404.png"></img>
<div class="error-text">
<div class="error-text1">抱歉,您访问的页面不存在!</div>
<div class="error-text2">您要找的页面存在,请返回 <a on-click={this.gotoIndexView}>首页</a> 继续浏览</div>
</div>
</div>
</div>
);
}
}
\ No newline at end of file
html, body {
height: 100%;
}
.app-error-view {
height: 100%;
width: 100%;
position: relative;
.app-error-container {
height: 380px;
width: 670px;
position: absolute;
top: calc((100% - 400px) / 2);
left: calc((100% - 670px) / 2);
display: flex;
align-items: center;
.error-text {
padding-left: 20px;
.error-text1 {
font-size: 20px;
margin-bottom: 20px;
}
.error-text2 {
font-size: 14px;
}
}
}
}
\ No newline at end of file
import { Vue, Component } from 'vue-property-decorator';
import './500.less';
@Component({})
export default class Error500 extends Vue {
/**
* 跳转首页
*
* @memberof Error404
*/
public gotoIndexView() {
this.$router.push('/');
}
/**
* 绘制内容
*
* @returns
* @memberof Error404
*/
public render() {
return (
<div class="app-error-view">
<div class="app-error-container">
<img src="/assets/img/500.png"></img>
<div class="error-text">
<div class="error-text1">抱歉,服务器出错了!</div>
<div class="error-text2">服务器出错了,请返回 <a on-click={this.gotoIndexView}>首页</a> 继续浏览</div>
</div>
</div>
</div>
);
}
}
\ No newline at end of file
.ivu-auto-complete {
.ivu-select-dropdown-list {
height: 300px;
}
}
import { Component, Vue, Prop, Model, Watch } from 'vue-property-decorator';
import './app-autocomplete.less';
import { Subject } from 'rxjs';
import { debounceTime, distinctUntilChanged } from 'rxjs/operators';
@Component({})
export default class AppAutocomplete extends Vue {
/**
* 表单数据
*
* @type {*}
* @memberof AppAutocomplete
*/
@Prop() public data: any;
/**
* 是否启用
*
* @type {boolean}
* @memberof AppAutocomplete
*/
@Prop() public disabled?: boolean;
/**
* 属性项名称
*
* @type {string}
* @memberof AppAutocomplete
*/
@Prop() public name!: string;
/**
* 值项名称
*
* @type {string}
* @memberof AppAutocomplete
*/
@Prop() public valueitem?: string;
/**
* 值
*
* @type {*}
* @memberof AppPicker
*/
@Model('change') public value?: any;
/**
* 当前值
*
* @type {string}
* @memberof AppPicker
*/
public curvalue: string = '';
/**
* 远程请求url 地址
*
* @type {string}
* @memberof AppAutocomplete
*/
@Prop() public url?: string;
/**
* 数组
*
* @type {any[]}
* @memberof AppAutocomplete
*/
public items: any[] = [];
/**
* 输入状态
*
* @type {boolean}
* @memberof AppAutocomplete
*/
public inputState: boolean = false;
/**
* 值变化
*
* @param {*} newVal
* @param {*} oldVal
* @memberof AppPicker
*/
@Watch('value')
public onValueChange(newVal: any, oldVal: any) {
this.curvalue = newVal;
}
/**
* 执行搜索数据
* @param query
* @param callback
*/
public onSearch(query: any, callback: any): void {
query = !query ? '' : query;
if (!this.inputState && Object.is(query, this.value)) {
query = '';
}
this.inputState = false;
const url = `${this.url}${this.name}/ac`;
let param: any = {};
Object.assign(param, this.data);
// 清除值项
if (this.valueitem) {
delete param[this.valueitem];
}
Object.assign(param, { [this.name]: query });
this.$http.post(url, param).then((response: any) => {
if (!response || response.status !== 200) {
this.$Notice.error({ title: '错误', desc: '请求异常' });
} else {
this.items = [...response.data];
}
if (callback) {
callback(this.items);
}
}).catch((error: any) => {
if (callback) {
callback([]);
}
});
}
/**
* 选中数据回调
* @param item
*/
public onACSelect(item: any): void {
if (this.name) {
this.$emit('formitemvaluechange', { name: this.name, value: item.text });
}
if (this.valueitem) {
this.$emit('formitemvaluechange', { name: this.valueitem, value: item.value });
}
}
/**
* 输入过程中
*
* @memberof AppAutocomplete
*/
public onInput($event: any) {
if (Object.is($event, this.value)) {
this.inputState = true;
}
}
/**
* 失去焦点事件
* @param e
*/
public onBlur(e: any): void {
let val: string = e.target.value;
if (!Object.is(val, this.value)) {
this.onACSelect({ text: val, value: '' });
}
this.$forceUpdate();
}
/**
* 清除
*/
public onClear($event: any): void {
if (this.name) {
this.$emit('formitemvaluechange', { name: this.name, value: '' });
}
if (this.valueitem) {
this.$emit('formitemvaluechange', { name: this.valueitem, value: '' });
}
this.$forceUpdate();
}
/**
* 绘制内容
*
* @returns
* @memberof AppAutocomplete
*/
public render() {
return (
<el-autocomplete class='text-value' value-key='text' disabled={this.disabled} v-model={this.curvalue} size='small'
trigger-on-focus={true} fetch-suggestions={(query: any, callback: any) => { this.onSearch(query, callback) }} on-select={(item: any) => { this.onACSelect(item) }}
on-input={($event: any) => this.onInput($event)} on-blur={($event: any) => { this.onBlur($event) }} style='width:100%;'>
<template slot='suffix'>
{(this.curvalue && !this.disabled) ? <i class='el-icon-circle-close' on-click={($event: any) => { this.onClear($event) }}></i> : ''}
<i class="el-icon-arrow-down"></i>
</template >
</el-autocomplete>
);
}
}
\ No newline at end of file
.app-checkbox-list {
overflow: auto;
}
\ No newline at end of file
import { Component, Vue, Prop, Model } from 'vue-property-decorator';
import './app-checkbox-list.less';
@Component({})
export default class AppCheckBox extends Vue {
/**
* 代码表标识
*
* @type {string}
* @memberof AppCheckBox
*/
@Prop() public tag?: string;
/**
* 是否禁用
*
* @type {boolean}
* @memberof AppCheckBox
*/
@Prop() disabled?: boolean;
/**
* 获取启用禁用状态
*
* @readonly
* @memberof AppCheckBox
*/
get isDisabled() {
if (this.disabled) {
return true;
} else {
return false;
}
}
/**
* 属性名称
*
* @type {*}
* @memberof AppCheckBox
*/
@Prop() name?: any;
/**
* 模式(数字或者字符串)
*
* @type {*}
* @memberof AppCheckBox
*/
@Prop() mode: any;
/**
* 当前模式
*
* @readonly
* @memberof AppCheckBox
*/
get currentmode() {
if (this.mode) {
return this.mode;
} else {
return 'str';
}
}
/**
* 分隔符
*
* @type {*}
* @memberof AppCheckBox
*/
@Prop() separator: any;
/**
* 获取分隔符
*
* @readonly
* @memberof AppCheckBox
*/
get currentseparator() {
if (this.separator) {
return this.separator;
} else {
return ';';
}
}
/**
* 选中值
*
* @type {*}
* @memberof AppCheckBox
*/
@Model('change') selects?: any;
/**
* 选中数组
*
* @memberof AppCheckBox
*/
get selectArray() {
if (this.selects) {
if (Object.is(this.currentmode, 'num') && this.items) {
let selectsArray: Array<any> = [];
let num: number = parseInt(this.selects, 10);
this.items.forEach((item: any) => {
if ((num & item.value) == item.value) {
selectsArray.push(item.value);
}
});
return selectsArray;
} else if (Object.is(this.currentmode, 'str')) {
if (this.selects !== '') {
return this.selects.split(this.currentseparator);
}
}
} else {
return [];
}
}
/**
* 设置选中
*
* @memberof AppCheckBox
*/
set selectArray(val: any) {
let value: null | string | number = null;
if (Object.is(this.currentmode, 'num')) {
let temp: number = 0;
val.forEach((item: any) => {
temp = temp | parseInt(item, 10);
});
value = temp;
} else if (Object.is(this.currentmode, 'str')) {
let _datas: string[] = [];
this.items.forEach((item: any) => {
const index = val.findIndex((_key: any) => Object.is(item.value, _key));
if (index === -1) {
return;
}
_datas.push(item.value);
});
value = _datas.join(this.currentseparator);
}
this.$emit('change', value);
}
/**
* 代码表数组
*
* @type {any[]}
* @memberof AppCheckBox
*/
public items: any[] = [];
/**
* vue 生命周期
*
* @memberof AppCheckBox
*/
public created() {
const codelist = this.$store.getters.getCodeList(this.tag);
if (codelist) {
this.items = [...JSON.parse(JSON.stringify(codelist.items))];
} else {
console.log(`----${this.tag}----代码表不存在`);
}
}
/**
* 渲染组件
*
* @returns
* @memberof AppCheckBox
*/
public render() {
return (
<checkbox-group class="app-checkbox-list" v-model={this.selectArray}>
{this.items.map((item: any) => {
return <checkbox label={item.value} disabled={this.isDisabled || item.disabled}>
<span>{item.text}</span>
</checkbox>
})}
</checkbox-group >
);
}
}
\ No newline at end of file
.codecss {
font-size: 18px;
font-weight: 600;
font-family: Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif;
}
\ No newline at end of file
import { Component, Vue, Prop, Model, Watch } from 'vue-property-decorator';
import './app-code-editor.less';
import CodeMirror from 'codemirror'; // CodeMirror,必要
import "codemirror/theme/blackboard.css"; //主题
// import 'codemirror/addon/hint/show-hint.css';
// import 'codemirror/addon/hint/show-hint.js'; 自动填充
import 'codemirror/lib/codemirror.css'; // css,必要
import 'codemirror/mode/javascript/javascript'; // js的语法高亮
import 'codemirror/mode/clike/clike'; // java的语法高亮
import 'codemirror/mode/jsx/jsx'; // jsx的语法高亮
import 'codemirror/mode/sql/sql'; // sql的语法高亮
import 'codemirror/mode/xml/xml'; // xml的语法高亮
import 'codemirror/mode/htmlmixed/htmlmixed';// html的语法高亮
import 'codemirror/mode/vue/vue';// vue的语法高亮
@Component({})
export default class AppCodeEditor extends Vue {
/**
* 高度
*/
@Prop() height?: any;
/**
* 宽度
*/
@Prop() width?: any;
/**
* 传入代码类型
*/
@Prop() codetype?: any;
/**
* 是否禁用
*/
@Prop() disabled?: boolean;
/**
* 双向绑定编辑器的值
*/
@Prop() code: any;
/**
* 当前编辑器
*/
public currenteditor: any;
/**
* 初始化编辑器
*/
public mounted() {
this.init();
}
/**
* 初始化参数
*/
public initParam() {
let mime;
let isDisabled = this.disabled === true ? true : false;
let theme = 'blackboard'//设置主题,不设置的会使用默认主题
if (!this.codetype) {
mime = { name: "text/x-java" };//当前代码类型
} else {
if (Object.is(this.codetype, 'javascript')) {
mime = { name: "text/javascript" };
} else if (Object.is(this.codetype, 'java')) {
mime = { name: "text/x-java" };
} else if (Object.is(this.codetype, 'css')) {
mime = { name: "text/x-less" };
} else if (Object.is(this.codetype, 'html')) {
mime = { name: "text/html" };
} else if (Object.is(this.codetype, 'vue')) {
mime = { name: "script/x-vue" };
} else if (Object.is(this.codetype, 'jsx')) {
mime = { name: "text/jsx" };
} else if (Object.is(this.codetype, 'xml')) {
mime = { name: "application/xml" };
} else if (Object.is(this.codetype, 'sql')) {
mime = { name: "text/x-mysql" };
}
}
let result = {
mode: mime,//选择对应代码编辑器的语言,我这边选的是数据库,根据个人情况自行设置即可
indentWithTabs: true,
indentUnit: 4, // 缩进单位为4
styleActiveLine: true, // 当前行背景高亮
matchBrackets: true, // 括号匹配
lineWrapping: true, // 自动换行
lineNumbers: true,
cursorHeight: 0.85,//光标的高度
showCursorWhenSelecting: true,//是否处于活动状态时是否应绘制光标
theme: theme,
autofocus: true,
extraKeys: { 'Ctrl': 'autocomplete' },//自定义快捷键
readOnly: isDisabled
};
return result;
}
/**
* 初始化
*/
public init() {
let initParam = this.initParam();
const refs: any = this.$refs;
this.currenteditor = CodeMirror.fromTextArea(refs.editorcode, initParam);
let width = this.width ? this.width : '100%';
let height = this.height ? this.height : '400px';
this.currenteditor.setSize(width, height);
//代码自动提示功能,记住使用cursorActivity事件不要使用change事件,这是一个坑,那样页面直接会卡死
// this.currenteditor.on('cursorActivity', (editor:any) =>{
// editor.showHint();
// });
this.currenteditor.on('change', (editor: any) => {
this.$emit('change', editor.getValue());
});
}
/**
* 渲染组件
*/
public render() {
return (<div>
<textarea ref="editorcode" class="codecss" v-model={this.code}></textarea>
</div >);
}
}
\ No newline at end of file
.app-embed-picker {
.app-embed-value, .app-embed-placeholder {
line-height: 32px;
height: 32px;
}
.app-embed-placeholder {
color: #c1c1c1;
}
> .ivu-card {
> .ivu-card-body {
> .content-container {
margin: 0;
}
}
}
}
\ No newline at end of file
import { Vue, Component, Prop, Watch } from 'vue-property-decorator';
import './app-embed-picker.less';
import { CreateElement } from 'vue';
import { Subject, Subscription } from 'rxjs';
@Component({})
export default class AppEmbedPicker extends Vue {
/**
* 表单数据
*
* @type {*}
* @memberof AppPicker
*/
@Prop() public data!: any;
/**
* 值
*
* @type {*}
* @memberof AppEmbedPicker
*/
@Prop() public value: any;
/**
* 表单状态
*
* @type {Subject<any>}
* @memberof AppEmbedPicker
*/
@Prop() public formState!: Subject<any>
/**
* 视图状态事件
*
* @protected
* @type {(Subscription | undefined)}
* @memberof SelectType
*/
protected formStateEvent: Subscription | undefined;
/**
* 值项名称
*
* @type {string}
* @memberof AppPicker
*/
@Prop() public valueItem?: string;
/**
* 关联视图名称
*
* @type {string}
* @memberof AppPicker
*/
@Prop() public refviewname?: string;
/**
* 提示信息
*
* @type {string}
* @memberof AppEmbedPicker
*/
@Prop() public placeholder!: string;
/**
* 空值文本
*
* @type {string}
* @memberof EmbedPicker
*/
@Prop() public emptyText?: string;
/**
* 属性项名称
*
* @type {string}
* @memberof AppPicker
*/
@Prop() public name!: string;
/**
* 关联视图参数
*
* @type {*}
* @memberof AppEmbedPicker
*/
@Prop() public itemParam: any;
/**
* 是否忽略之变化
*
* @type {boolean}
* @memberof AppEmbedPicker
*/
@Prop() public ignorefieldvaluechange!: boolean;
/**
* 重置项
*
* @type {string}
* @memberof AppEmbedPicker
*/
@Prop() public refreshitems?: string;
/**
* 视图参数
*
* @type {string}
* @memberof AppEmbedPicker
*/
public srfparentdata: any = '';
/**
* 设置视图参数
*
* @memberof AppEmbedPicker
*/
public setViewParam(activeData: any) {
if (!this.itemParam || !activeData) {
return;
}
let arg: any = {};
if (this.itemParam.parentdata) {
let parentData: any = {};
Object.keys(this.itemParam.parentdata).every((name: string) => {
let value: string = this.itemParam.parentdata[name];
if (value.startsWith('%') && value.endsWith('%')) {
const key: string = value.substring(1, value.length - 1);
if (!activeData.hasOwnProperty(key)) {
this.$Notice.error({ title: '错误', desc: `操作失败,未能找到当前表单项${key},无法继续操作` });
return false;
}
value = activeData[key];
}
Object.assign(parentData, { [name]: value });
return true;
});
Object.assign(arg, parentData);
}
this.srfparentdata = arg;
}
/**
* 监控值
*
* @param {*} newVal
* @param {*} oldVal
* @memberof AppFormDRUIPart
*/
@Watch('data')
onActivedataChange(newVal: any, oldVal: any) {
const newFormData: any = JSON.parse(newVal);
const oldDormData: any = JSON.parse(oldVal);
this.setViewParam(newFormData);
if (!this.refreshitems || this.ignorefieldvaluechange) {
return;
}
if(Object.is(newFormData[this.refreshitems], oldDormData[this.refreshitems])) {
return;
}
this.setValue([{srfmajortext: null, srfkey: null}]);
let param = this.srfparentdata;
this.srfparentdata = {};
Object.assign(this.srfparentdata, param);
}
/**
* 生命周期
*
* @memberof AppEmbedPicker
*/
public created() {
if(this.formState) {
this.formStateEvent = this.formState.subscribe(({ tag, action, data }) => {
if (Object.is('load', action)) {
this.setViewParam(JSON.parse(this.data));
}
});
}
}
/**
* vue 生命周期
*
* @memberof SelectType
*/
public destroyed() {
if (this.formStateEvent) {
this.formStateEvent.unsubscribe();
}
}
/**
* 设置值
*
* @param {*} item
* @memberof AppEmbedPicker
*/
public setValue(item: any) {
if (this.name) {
this.$emit('formitemvaluechange', { name: this.name, value: item[0].srfmajortext });
}
if (this.valueItem) {
this.$emit('formitemvaluechange', { name: this.valueItem, value: item[0].srfkey });
}
}
/**
* 绘制内容
*
* @param {CreateElement} h
* @returns
* @memberof AppEmbedPicker
*/
public render(h: CreateElement) {
if (this.refviewname) {
return (
<div class="app-embed-picker">
<div style={{ height: this.placeholder ? 'calc(100% - 32px)' : '100%' }}>
{
this.$createElement(this.refviewname, {
props: {
viewdata: JSON.stringify({ srfparentdata: this.srfparentdata })
},
on: {
'viewdataschange': (args: any) => {
if (args && args.length > 0) {
this.setValue(args);
}
}
},
style: {
height: '100%'
}
})
}
</div>
{ this.placeholder ? ( this.value ? <div class="app-embed-value">{this.value}</div> : <div class="app-embed-placeholder">{this.placeholder}</div> ) : '' }
</div>
);
} else {
return (<div>{this.emptyText}</div>);
}
}
}
\ No newline at end of file
import { Vue, Component, Prop, Watch } from 'vue-property-decorator';
import './app-export-excel.less';
/**
* 数据导出组件
*
* @export
* @class AppExportExcel
* @extends {Vue}
*/
@Component({})
export default class AppExportExcel extends Vue {
/**
* 工具栏项
*
* @type {*}
* @memberof AppExportExcel
*/
@Prop() public item?: any;
/**
* 工具栏项层级
*
* @type {number}
* @memberof AppExportExcel
*/
@Prop({ default: 0 }) public itemLevel!: number;
/**
* 起始页
*
* @type {(string | null)}
* @memberof AppExportExcel
*/
public startPage: string | null = null;
/**
* 结束页
*
* @type {(string | null)}
* @memberof AppExportExcel
*/
public endPage: string | null = null;
/**
* 是否显示下拉菜单
*
* @type {boolean}
* @memberof AppExportExcel
*/
public visible: boolean = false;
/**
* 点击触发相似
*
* @memberof AppExportExcel
*/
public clickVisible(): void {
this.visible = !this.visible
}
/**
* 导出数据
*
* @param {*} $event
* @param {string} type
* @returns {void}
* @memberof AppExportExcel
*/
public exportExcel($event: any, type: string): void {
const exportparms: any = { type: type };
if (Object.is(type, 'maxRowCount')) {
Object.assign(exportparms, { maxRowCount: this.item.MaxRowCount })
this.visible = false;
} else if (Object.is(type, 'activatedPage')) {
this.visible = false;
} else if (Object.is(type, 'custom')) {
if (!this.startPage || !this.endPage) {
this.$Notice.warning({ title: '警告', desc: '请输入起始页' });
return;
}
const startPage: any = Number.parseInt(this.startPage, 10);
const endPage: any = Number.parseInt(this.endPage, 10);
if (Number.isNaN(startPage) || Number.isNaN(endPage)) {
this.$Notice.warning({ title: '警告', desc: '请输入有效的起始页' });
return;
}
if (startPage < 1 || endPage < 1 || startPage > endPage) {
this.$Notice.warning({ title: '警告', desc: '请输入有效的起始页' });
return;
}
this.startPage = null;
this.endPage = null;
Object.assign(exportparms, { startPage: startPage, endPage: endPage });
this.visible = false;
}
if (!this.visible) {
Object.assign($event, { exportparms: exportparms });
this.$emit('exportexcel', $event);
}
}
/**
* 绘制默认内容
*
* @returns
* @memberof AppExportExcel
*/
public renderDefault() {
return (
<dropdown trigger='custom' transfer={true} visible={this.visible}>
<i-button disabled={this.item.disabled} on-click={() => this.clickVisible()}>
<i class='fa fa-file-excel-o'></i>
<span class='caption'>{this.item.caption}</span>
</i-button>
<dropdown-menu slot='list'>
<dropdown-item>
<p on-click={($event: any) => this.exportExcel($event, 'maxRowCount')}>
{this.item.caption}全部(最大{this.item.caption}{this.item.MaxRowCount}行)
</p>
</dropdown-item>
<dropdown-item>
<p on-click={($event: any) => this.exportExcel($event, 'activatedPage')}>
{this.item.caption}当前页
</p>
</dropdown-item>
<dropdown-item>
{this.item.caption}&nbsp;
<i-input style="width: 30px;" v-model={this.startPage}> </i-input>&nbsp;&nbsp;
<i-input style="width: 30px;" v-model={this.endPage}></i-input>&nbsp;
<i-button on-click={($event: any) => this.exportExcel($event, 'custom')}>Go!</i-button>
</dropdown-item>
</dropdown-menu>
</dropdown>
);
}
/**
* 绘制临时方案
*
* @returns
* @memberof AppExportExcel
*/
public renderTeml() {
return (
<dropdown transfer={true} trigger='click'>
<i-button disabled={this.item.disabled}>
<i class='fa fa-file-excel-o'></i>
<span class='caption'>{this.item.caption}</span>
</i-button>
<dropdown-menu slot='list'>
<dropdown-item>
<p on-click={($event: any) => this.exportExcel($event, 'maxRowCount')}>
{this.item.caption}全部(最大{this.item.caption}{this.item.MaxRowCount}行)
</p>
</dropdown-item>
<dropdown-item>
<p on-click={($event: any) => this.exportExcel($event, 'activatedPage')}>
{this.item.caption}当前页
</p>
</dropdown-item>
</dropdown-menu>
</dropdown>
);
}
/**
* 绘制内容
*
* @returns
* @memberof AppExportExcel
*/
public render() {
if (this.itemLevel === 0) {
return this.renderTeml();
}
}
}
\ No newline at end of file
import { Component, Vue, Prop, Watch } from 'vue-property-decorator';
import './app-file-upload.less';
import { Environment } from '@/environments/environment';
import { CreateElement } from 'vue';
import { Subject, Unsubscribable } from 'rxjs';
@Component({})
export default class AppFileUpload extends Vue {
/**
* 表单状态
*
* @type {Subject<any>}
* @memberof AppFileUpload
*/
@Prop() public formState?: Subject<any>
/**
* 是否忽略表单项书香值变化
*
* @type {boolean}
* @memberof AppFileUpload
*/
@Prop() public ignorefieldvaluechange?: boolean;
/**
* 表单状态事件
*
* @private
* @type {(Unsubscribable | undefined)}
* @memberof AppFileUpload
*/
private formStateEvent: Unsubscribable | undefined;
/**
* 表单数据
*
* @type {string}
* @memberof AppFileUpload
*/
@Prop() public data!: string;
/**
* 初始化值
*
* @type {*}
* @memberof AppFileUpload
*/
@Prop() public value?: any;
/**
* 数据值变化
*
* @param {*} newval
* @param {*} val
* @memberof AppFileUpload
*/
@Watch('value')
onValueChange(newval: any, val: any) {
if (this.ignorefieldvaluechange) {
return;
}
if (newval) {
this.files = JSON.parse(newval);
this.dataProcess();
} else {
this.files = [];
}
}
/**
* 所属表单项名称
*
* @type {string}
* @memberof AppFileUpload
*/
@Prop() public name!: string;
/**
* 是否禁用
*
* @type {boolean}
* @memberof AppFileUpload
*/
@Prop() public disabled?: boolean;
/**
* 上传参数
*
* @type {string}
* @memberof AppFileUpload
*/
@Prop() public uploadparams?: string;
/**
* 下载参数
*
* @type {string}
* @memberof AppFileUpload
*/
@Prop() public exportparams?: string;
/**
* 自定义参数
*
* @type {*}
* @memberof AppFileUpload
*/
@Prop() public customparams?: any;
/**
* 上传文件路径
*
* @memberof AppFileUpload
*/
public uploadUrl = Environment.BaseUrl + Environment.UploadFile;
/**
* 下载文件路径
*
* @memberof AppFileUpload
*/
public downloadUrl = Environment.BaseUrl + Environment.ExportFile;
/**
* 文件列表
*
* @memberof AppFileUpload
*/
public files = [];
/**
* 上传keys
*
* @type {Array<any>}
* @memberof AppFileUpload
*/
public upload_keys: Array<any> = [];
/**
* 导出keys
*
* @type {Array<any>}
* @memberof AppFileUpload
*/
public export_keys: Array<any> = [];
/**
* 自定义数组
*
* @type {Array<any>}
* @memberof AppFileUpload
*/
public custom_arr: Array<any> = [];
/**
* 应用参数
*
* @type {*}
* @memberof AppImageUpload
*/
public appData: any;
/**
* 数据处理
*
* @private
* @memberof AppFileUpload
*/
private dataProcess(): void {
let upload_arr: Array<string> = [];
let export_arr: Array<string> = [];
const _data: any = JSON.parse(this.data);
this.upload_keys.forEach((key: string) => {
upload_arr.push(`${key}=${_data[key]}`);
});
this.export_keys.forEach((key: string) => {
export_arr.push(`${key}=${_data[key]}`);
});
let _url = `${Environment.BaseUrl}${Environment.UploadFile}`;
if (upload_arr.length > 0 || this.custom_arr.length > 0) {
_url = `${_url}?${upload_arr.join('&')}${upload_arr.length > 0 ? '&' : ''}${this.custom_arr.join('&')}`;
}
this.uploadUrl = _url;
this.files.forEach((file: any) => {
let url = `${this.downloadUrl}/${file.id}`;
if (upload_arr.length > 0 || this.custom_arr.length > 0) {
url = `${url}?${upload_arr.join('&')}${upload_arr.length > 0 ? '&' : ''}${this.custom_arr.join('&')}`;
}
file.url = url;
});
}
/**
* vue 生命周期
*
* @memberof AppFileUpload
*/
public created() {
if (this.formState) {
this.formStateEvent = this.formState.subscribe(($event: any) => {
// 表单加载完成
if (Object.is($event.type, 'load')) {
if (this.value) {
this.files = JSON.parse(this.value);
}
this.dataProcess();
}
});
}
}
/**
* vue 生命周期
*
* @returns
* @memberof AppFileUpload
*/
public mounted() {
this.appData = this.$store.getters.getAppData();
let uploadparams: string = '';
let exportparams: string = '';
if (this.uploadparams && !Object.is(this.uploadparams, '')) {
uploadparams = this.uploadparams;
}
if (this.exportparams && !Object.is(this.exportparams, '')) {
exportparams = this.exportparams;
}
let upload_keys: Array<string> = uploadparams.split(';');
let export_keys: Array<string> = exportparams.split(';');
let custom_arr: Array<string> = [];
if (this.customparams && !Object.is(this.customparams, '')) {
Object.keys(this.customparams).forEach((name: string) => {
custom_arr.push(`${name}=${this.customparams[name]}`);
});
}
this.upload_keys = upload_keys;
this.export_keys = export_keys;
this.custom_arr = custom_arr;
if (this.value) {
this.files = JSON.parse(this.value);
}
this.dataProcess();
}
/**
* 组件销毁
*
* @memberof AppFileUpload
*/
public destroyed(): void {
if (this.formStateEvent) {
this.formStateEvent.unsubscribe();
}
}
/**
* 上传之前
*
* @param {*} file
* @memberof AppFileUpload
*/
public beforeUpload(file: any) {
// console.log('上传之前');
}
/**
* 上传成功回调
*
* @param {*} response
* @param {*} file
* @param {*} fileList
* @memberof AppFileUpload
*/
public onSuccess(response: any, file: any, fileList: any) {
if (!response) {
return;
}
const data = { name: response.name, id: response.id };
let arr: Array<any> = [];
this.files.forEach((_file:any) => {
arr.push({name: _file.name, id: _file.id})
});
arr.push(data);
let value: any = arr.length > 0 ? JSON.stringify(arr) : null;
this.$emit('formitemvaluechange', { name: this.name, value: value });
}
/**
* 上传失败回调
*
* @param {*} error
* @param {*} file
* @param {*} fileList
* @memberof AppFileUpload
*/
public onError(error: any, file: any, fileList: any) {
this.$Notice.error({ title: '上传失败' });
}
/**
* 删除文件
*
* @param {*} file
* @param {*} fileList
* @memberof AppFileUpload
*/
public onRemove(file: any, fileList: any) {
let arr: Array<any> = [];
fileList.forEach((f: any) => {
if (f.id != file.id) {
arr.push({ name: f.name, id: f.id });
}
});
let value: any = arr.length > 0 ? JSON.stringify(arr) : null;
this.$emit('formitemvaluechange', { name: this.name, value: value });
}
/**
* 下载文件
*
* @param {*} file
* @memberof AppFileUpload
*/
public onDownload(file: any) {
window.open(file.url);
}
/**
* 绘制内容
*
* @param {CreateElement} h
* @returns
* @memberof AppFileUpload
*/
public render(h: CreateElement) {
return (
this.$createElement(
'el-upload',
{
props: {
disabled: this.disabled,
'file-list': this.files,
action: this.uploadUrl,
headers: { srfappdata: this.appData },
'before-upload': (file: any) => this.beforeUpload(file),
'on-success': (response: any, file: any, fileList: any) => this.onSuccess(response, file, fileList),
'before-remove': (file: any, fileList: any) => this.onRemove(file, fileList),
'on-error': (error: any, file: any, fileList: any) => this.onError(error, file, fileList),
'on-preview': (file: any) => this.onDownload(file),
}
},
[
this.renderElButton(),
]
)
);
}
/**
* 绘制按钮提示框
*
* @returns
* @memberof AppFileUpload
*/
public renderElButton() {
return (
<el-button size='small' icon='el-icon-upload' disabled={this.disabled}>{this.$t('app.fileUpload.caption')}</el-button>
);
}
}
\ No newline at end of file
.form-druipart {
position: relative;
}
\ No newline at end of file
import { Vue, Component, Prop, Watch } from 'vue-property-decorator';
import { Subject, Unsubscribable } from 'rxjs';
import './app-form-druipart.less';
@Component({})
export default class AppFormDRUIPart extends Vue {
/**
* 表单数据
*
* @type {string}
* @memberof AppFormDRUIPart
*/
@Prop() public data!: string;
/**
* 关联视图
*
* @type {string}
* @memberof AppFormDRUIPart
*/
@Prop() public viewname?: string;
/**
* 刷新关系项
*
* @type {string}
* @memberof AppFormDRUIPart
*/
@Prop({ default: '' }) public refreshitems!: string;
/**
* 关系视图类型
*
* @type {string}
* @memberof AppFormDRUIPart
*/
@Prop() public refviewtype?: string;
/**
* 父数据
*
* @type {*}
* @memberof AppFormDRUIPart
*/
@Prop() public parentdata!: any;
/**
* 传入参数项名称
*
* @type {string}
* @memberof AppFormDRUIPart
*/
@Prop() public paramitem!: string;
/**
* 是否忽略表单项值变化
*
* @type {boolean}
* @memberof AppFormDRUIPart
*/
@Prop() public ignorefieldvaluechange!: boolean;
/**
* 表单状态
*
* @type {Subject<any>}
* @memberof AppFormDRUIPart
*/
@Prop() public formState!: Subject<any>
/**
* 表单状态事件
*
* @private
* @type {(Unsubscribable | undefined)}
* @memberof AppFormDRUIPart
*/
private formStateEvent: Unsubscribable | undefined;
/**
* 监控值
*
* @param {*} newVal
* @param {*} oldVal
* @memberof AppFormDRUIPart
*/
@Watch('data')
onActivedataChange(newVal: any, oldVal: any) {
if (this.ignorefieldvaluechange) {
return;
}
if (Object.is(newVal, oldVal)) {
return;
}
const newFormData: any = JSON.parse(newVal);
const oldDormData: any = JSON.parse(oldVal);
let refreshRefview = false;
this.hookItems.some((_hookItem: any) => {
if (!Object.is(newFormData[_hookItem], oldDormData[_hookItem])) {
refreshRefview = true;
return refreshRefview;
}
return refreshRefview;
});
if (refreshRefview) {
this.refreshDRUIPart();
}
}
/**
* 是否启用遮罩
*
* @type {boolean}
* @memberof AppFormDRUIPart
*/
public blockUI: boolean = false;
/**
* 遮罩提示信息
*
* @type {string}
* @memberof AppFormDRUIPart
*/
public blockUITipInfo: string = '请先保存主数据';
/**
* 是否刷新关系数据
*
* @private
* @type {boolean}
* @memberof AppFormDRUIPart
*/
private isRelationalData: boolean = true;
/**
* 刷新节点
*
* @private
* @type {string[]}
* @memberof AppFormDRUIPart
*/
private hookItems: string[] = [];
/**
* 父数据
*
* @type {*}
* @memberof AppFormDRUIPart
*/
public srfparentdata: any = {};
/**
* 刷新关系页面
*
* @private
* @returns {void}
* @memberof AppFormDRUIPart
*/
private refreshDRUIPart(): void {
if (Object.is(this.parentdata.SRFPARENTTYPE, 'CUSTOM')) {
this.isRelationalData = false;
}
const formData: any = JSON.parse(this.data);
const _paramitem = formData[this.paramitem];
this.srfparentdata = {};
Object.assign(this.srfparentdata, this.parentdata);
Object.assign(this.srfparentdata, { srfparentkey: _paramitem });
if (this.isRelationalData) {
if (!_paramitem || _paramitem == null || Object.is(_paramitem, '')) {
this.blockUIStart();
return;
} else {
this.blockUIStop();
}
}
// this.$forceUpdate();
}
/**
* vue 生命周期
*
* @memberof AppFormDRUIPart
*/
public created(): void {
this.hookItems = [...this.refreshitems.split(';')];
if (!this.formState) {
return;
}
if (!Object.is(this.paramitem, 'srfkey')) {
this.hookItems.push(this.paramitem);
}
this.formStateEvent = this.formState.subscribe(($event: any) => {
// 表单加载完成
if (Object.is($event.type, 'load')) {
this.refreshDRUIPart();
}
// 表单保存完成
if (Object.is($event.type, 'save')) {
this.refreshDRUIPart();
}
// 表单项更新
if (Object.is($event.type, 'updateformitem')) {
if (!$event.data) {
return;
}
let refreshRefview = false;
Object.keys($event.data).some((name: string) => {
const index = this.hookItems.findIndex((_name: string) => Object.is(_name, name));
refreshRefview = index !== -1 ? true : false;
return refreshRefview;
});
if (refreshRefview) {
this.refreshDRUIPart();
}
}
});
this.refreshDRUIPart();
}
/**
* 部件销毁
*
* @memberof AppFormDRUIPart
*/
public destroyed(): void {
if (this.formStateEvent) {
this.formStateEvent.unsubscribe();
}
}
/**
* 开启遮罩
*
* @private
* @memberof AppFormDRUIPart
*/
private blockUIStart(): void {
this.blockUI = true;
}
/**
* 关闭遮罩
*
* @private
* @memberof AppFormDRUIPart
*/
private blockUIStop(): void {
this.blockUI = false;
}
/**
* 绘制内容
*
* @returns
* @memberof AppFormDRUIPart
*/
public render() {
return (
<div class='form-druipart'>
{
(this.viewname && !Object.is(this.viewname, '')) ?
this.$createElement(this.viewname, {
class: {
viewcontainer2: true,
},
props: {
viewdata: JSON.stringify({ srfparentdata: this.srfparentdata })
},
on: {
mditemsload: ($event: any) => {
console.log('多数据视图加载完成,触发后续表单项更新');
},
drdatasaved: ($event: any) => {
console.log('DEMEDITVIEW9 关系数据保存完成');
},
drdatachange: ($event: any) => {
console.log('DEMEDITVIEW9 关系数据值变化');
},
viewdataschange: ($event: any) => {
console.log('视图数据变化');
},
viewload: ($event: any) => {
console.log('视图加载完成');
}
},
key: this.$util.createUUID(),
})
: ''
}
{this.blockUI ? <spin class="app-druipart-spin" fix >{this.blockUITipInfo}</spin> : ''}
</div>
);
}
}
\ No newline at end of file
.app-form-group {
>.ivu-card-head {
>p {
>i {
margin-right: 8px;
cursor: pointer;
}
}
}
>.ivu-card-extra {
.item-extract-mode {
.item {
margin-left: 12px;
}
}
}
}
.app-form-group.app-group-collapse-contant {
.ivu-card-body {
display: none;
}
}
.app-group-flex {
height: 100%;
overflow: auto;
> .ivu-card-body {
height: calc(100% - 51px);
overflow: auto;
}
}
\ No newline at end of file
import { Vue, Component, Prop } from 'vue-property-decorator';
import './app-form-group.less';
@Component({})
export default class AppFormGroup extends Vue {
/**
* 标题
*
* @type {string}
* @memberof AppFormGroup
*/
@Prop() public caption?: string;
/**
* 内置界面样式
*
* @type {string}
* @memberof AppFormGroup
*/
@Prop() public uiStyle?: string;
/**
* 布局模式
*
* @type {string}
* @memberof AppFormGroup
*/
@Prop() public layoutType?: string;
/**
* 是否显示标题
*
* @type {boolean}
* @memberof AppFormGroup
*/
@Prop({ default: true }) public isShowCaption!: boolean;
/**
* 信息面板模式
*
* @type {boolean}
* @memberof AppFormGroup
*/
@Prop({ default: false }) public isInfoGroupMode!: boolean;
/**
* 界面行为组
*
* @type {*}
* @memberof AppFormGroup
*/
@Prop() public uiActionGroup?: any;
/**
* 标题栏关闭模式
* 0: 不支持关闭
* 1: 默认打开
* 2: 默认关闭
*
* @type {(number | 0 | 1 | 2)}
* @memberof AppFormGroup
*/
@Prop({ default: 0 }) public titleBarCloseMode!: number | 0 | 1 | 2;
/**
* 收缩内容
*
* @type {boolean}
* @memberof AppFormGroup
*/
public collapseContant: boolean = false;
/**
* 计算样式
*
* @readonly
* @type {string[]}
* @memberof AppFormGroup
*/
get classes(): string[] {
return [
'app-form-group',
this.isShowCaption && this.collapseContant ? 'app-group-collapse-contant' : '',
this.isInfoGroupMode ? 'app-info-group-mode' : '',
Object.is(this.layoutType, 'FLEX') ? 'app-group-flex' : '',
this.isShowCaption ? '' : 'app-group-hiddden-caption',
];
}
/**
* vue 生命周期
*
* @memberof AppFormGroup
*/
public created() {
this.collapseContant = this.titleBarCloseMode === 2 ? true : false;
}
/**
* 触发收缩
*
* @memberof AppFormGroup
*/
public clickCollapse(): void {
this.collapseContant = !this.collapseContant;
}
/**
* 执行界面行
*
* @param {*} $event
* @memberof AppFormGroup
*/
public doUIAction($event: any, item: any): void {
this.$emit('groupuiactionclick', { event: $event, item: item });
}
/**
* 绘制界面行为项
*
* @param {*} item
* @returns
* @memberof AppFormGroup
*/
public renderActionItem(item: any) {
return (
<span class='item' on-click={($event: any) => this.doUIAction($event, item)}>
{
item.icon && !Object.is(item.icon, '') ?
<i class={item.icon} ></i> :
item.img && !Object.is(item.img, '') ?
<img src={item.img} /> :
''
}
&nbsp;
<span>
{
this.uiActionGroup.langbase && !Object.is(this.uiActionGroup.langbase, '')
&& item.uiactiontag && !Object.is(item.uiactiontag, '') ?
this.$t(`${this.uiActionGroup.langbase}.uiactions.${item.uiactiontag}`)
: item.caption
}
</span>
</span>
);
}
/**
* 绘制逐项展开
*
* @returns
* @memberof AppFormGroup
*/
public renderItemExtractMode() {
return (
<span class='item-extract-mode'>
{
this.uiActionGroup.details && Array.isArray(this.uiActionGroup.details) ?
this.uiActionGroup.details.map((detail: any) => {
return this.renderActionItem(detail);
})
:
''
}
</span>
);
}
/**
* 绘制分组展开项
*
* @returns
* @memberof AppFormGroup
*/
public renderItemsExtractMode() {
return (
<dropdown transfer={true} trigger='click'>
<a href='javascript:void(0)'>
{this.uiActionGroup.caption}
</a>
{
this.uiActionGroup.details && Array.isArray(this.uiActionGroup.details) ?
<dropdown-menu slot='list'>
{
this.uiActionGroup.details.map((detail: any) => {
return (
<dropdown-item name={detail.name}>{this.renderActionItem(detail)}</dropdown-item>
);
})
}
</dropdown-menu>
: ''
}
</dropdown>
);
}
/**
* 绘制界面行为组
*
* @returns
* @memberof AppFormGroup
*/
public renderUIActionGroup() {
return (
<a slot='extra'>
{
this.uiActionGroup.extractMode && Object.is(this.uiActionGroup.extractMode, 'ITEMS') ?
this.renderItemsExtractMode() :
this.renderItemExtractMode()
}
</a >
);
}
/**
* 绘制标题收缩模式
*
* @returns
* @memberof AppFormGroup
*/
public renderTitleBarCloseMode() {
return (
this.titleBarCloseMode !== 0 ?
<icon
type={this.collapseContant ? 'ios-arrow-dropright-circle' : 'ios-arrow-dropdown-circle'}
on-click={() => this.clickCollapse()}>
</icon>
: ''
);
}
/**
* 内容绘制
*
* @memberof AppFormGroup
*/
public render() {
if (Object.is(this.uiStyle, 'STYLE2')) {
return (
<app-form-group2
caption={this.caption}
uiStyle={this.uiStyle}
layoutType={this.layoutType}
isShowCaption={this.isShowCaption}
uiActionGroup={this.uiActionGroup}
titleBarCloseMode={this.titleBarCloseMode}>
{this.$slots.default}
</app-form-group2>
);
} else {
return (
this.isShowCaption ?
<card bordered={false} dis-hover={true} class={this.classes}>
<p class='' slot='title'>
{this.renderTitleBarCloseMode()}
{this.caption}
</p>
{this.uiActionGroup ? this.renderUIActionGroup() : ''}
{Object.is(this.layoutType, 'FLEX') ? this.$slots.default : <row gutter={10}> {this.$slots.default} </row>}
</card> :
<row class={this.classes}>
{this.$slots.default}
</row>
);
}
}
}
\ No newline at end of file
import { Vue, Component, Prop, } from 'vue-property-decorator';
import './app-form-group2.less';
@Component({})
export default class AppFormGroup2 extends Vue {
/**
* 标题
*
* @type {string}
* @memberof AppFormGroup2
*/
@Prop() public caption?: string;
/**
* 内置界面样式
*
* @type {string}
* @memberof AppFormGroup2
*/
@Prop() public uiStyle?: string;
/**
* 布局模式
*
* @type {string}
* @memberof AppFormGroup
*/
@Prop() public layoutType?: string;
/**
* 是否显示标题
*
* @type {boolean}
* @memberof AppFormGroup2
*/
@Prop({ default: true }) public isShowCaption!: boolean;
/**
* 界面行为组
*
* @type {*}
* @memberof AppFormGroup2
*/
@Prop() public uiActionGroup?: any;
/**
* 标题栏关闭模式
* 0: 不支持关闭
* 1: 默认打开
* 2: 默认关闭
*
* @type {(number | 0 | 1 | 2)}
* @memberof AppFormGroup2
*/
@Prop({ default: 0 }) public titleBarCloseMode!: number | 0 | 1 | 2;
/**
* 绘制内容
*
* @returns
* @memberof AppFormGroup2
*/
public render() {
return (
<span>未实现</span>
);
}
}
\ No newline at end of file
.app-form-item {
// margin-bottom: 16px;
>.ivu-form-item-label {
text-decoration: none;
display: block;
overflow: hidden;
white-space: nowrap;
}
>.ivu-form-item-content {
min-height: 36px;
}
}
.app-form-item-label-top {
>.ivu-form-item-label {
float: none;
display: inline-block;
padding: 0 0 10px;
}
}
\ No newline at end of file
import { Vue, Component, Prop, Watch } from 'vue-property-decorator';
import './app-form-item.less';
@Component({})
export default class AppFormItem extends Vue {
/**
* 名称
*
* @type {string}
* @memberof AppFormItem
*/
@Prop() public caption!: string;
/**
* 错误信息
*
* @type {string}
* @memberof AppFormItem
*/
@Prop() public error?: string;
/**
* 标签位置
*
* @type {(string | 'BOTTOM' | 'LEFT' | 'NONE' | 'RIGHT' | 'TOP')}
* @memberof AppFormItem
*/
@Prop() public labelPos?: string | 'BOTTOM' | 'LEFT' | 'NONE' | 'RIGHT' | 'TOP';
/**
* 标签宽度
*
* @type {number}
* @memberof AppFormItem
*/
@Prop({}) public labelWidth!: number;
/**
* 是否显示标题
*
* @type {boolean}
* @memberof AppFormItem
*/
@Prop() public isShowCaption?: boolean;
/**
* 标签是否空白
*
* @type {boolean}
* @memberof AppFormItem
*/
@Prop() public isEmptyCaption?: boolean;
/**
* 表单项名称
*
* @type {string}
* @memberof AppFormItem
*/
@Prop() public name!: string;
/**
* 内置样式
*
* @type {string}
* @memberof AppFormItem
*/
@Prop() public uiStyle?: string;
/**
* 表单项值规则
*
* @type {string}
* @memberof AppFormItem
*/
@Prop() public itemRules!: string;
/**
* 值规则数组
*
* @type {any[]}
* @memberof AppFormItem
*/
public rules: any[] = [];
/**
* 是否必填
*
* @type {boolean}
* @memberof AppFormItem
*/
public required: boolean = false;
/**
* 表单项值规则监控
*
* @param {*} newVal
* @param {*} oldVal
* @memberof AppFormItem
*/
@Watch('itemRules')
onItemRulesChange(newVal: any, oldVal: any) {
if (newVal) {
try {
this.rules = [];
const _rules: any[] = JSON.parse(newVal);
this.rules = [..._rules];
this.rules.some((rule: any) => {
if (rule.hasOwnProperty('required')) {
this.required = rule.required;
return true;
}
return false;
});
} catch (error) {
}
}
}
/**
* 计算样式
*
* @readonly
* @type {string []}
* @memberof AppFormItem
*/
get classes(): string[] {
return [
'app-form-item',
Object.is(this.labelPos, 'TOP') ? 'app-form-item-label-top' : ''
];
}
/**
* vue 生命周期
*
* @memberof AppFormItem
*/
public mounted() {
if (this.itemRules) {
try {
const _rules: any[] = JSON.parse(this.itemRules);
this.rules = [..._rules];
this.rules.some((rule: any) => {
if (rule.hasOwnProperty('required')) {
this.required = rule.required;
return true;
}
return false;
});
} catch (error) {
}
}
}
/**
* 绘制内容
*
* @returns
* @memberof AppFormItem
*/
public render() {
if (Object.is(this.uiStyle, 'STYLE2')) {
return (
<app-form-item2
caption={this.caption}
error={this.error}
labelPos={this.labelPos}
labelWidth={this.labelWidth}
isShowCaption={this.isShowCaption}
isEmptyCaption={this.isEmptyCaption}
name={this.name}
uiStyle={this.uiStyle}
itemRules={this.itemRules}>
{this.$slots.default}
</app-form-item2>
);
} else {
return (
<form-item
prop={this.name}
error={this.error}
required={this.required}
rules={this.rules}
class={this.classes}
label-width={this.isShowCaption ? !Object.is(this.labelPos, 'TOP') ? this.labelWidth : null : 0}>
{
this.isShowCaption && this.labelWidth > 0 ?
<span slot='label'>
{this.isEmptyCaption ? '' : this.caption}
</span>
: ''
}
{this.$slots.default}
</form-item>
);
}
}
}
\ No newline at end of file
.app-form-item2 {
margin-bottom: 12px;
>.ivu-form-item-label {
text-decoration: none;
display: block;
overflow: hidden;
white-space: nowrap;
}
>.ivu-form-item-content {
min-height: 36px;
display: flex;
.app-editor-contant {
flex-grow: 1;
}
.app-error-tip {
width: 20px;
}
}
.ivu-form-item-error-tip {
display: none;
}
}
.app-form-item-label-top {
>.ivu-form-item-label {
float: none;
display: inline-block;
padding: 0 0 10px;
}
}
\ No newline at end of file
import { Vue, Component, Prop, Watch } from 'vue-property-decorator';
import './app-form-item2.less';
@Component({})
export default class AppFormItem2 extends Vue {
/**
* 名称
*
* @type {string}
* @memberof AppFormItem2
*/
@Prop() public caption!: string;
/**
* 错误信息
*
* @type {string}
* @memberof AppFormItem2
*/
@Prop() public error?: string;
/**
* 标签位置
*
* @type {(string | 'BOTTOM' | 'LEFT' | 'NONE' | 'RIGHT' | 'TOP')}
* @memberof AppFormItem2
*/
@Prop() public labelPos?: string | 'BOTTOM' | 'LEFT' | 'NONE' | 'RIGHT' | 'TOP';
/**
* 标签宽度
*
* @type {number}
* @memberof AppFormItem2
*/
@Prop({}) public labelWidth!: number;
/**
* 是否显示标题
*
* @type {boolean}
* @memberof AppFormItem2
*/
@Prop() public isShowCaption?: boolean;
/**
* 标签是否空白
*
* @type {boolean}
* @memberof AppFormItem2
*/
@Prop() public isEmptyCaption?: boolean;
/**
* 表单项名称
*
* @type {string}
* @memberof AppFormItem2
*/
@Prop() public name!: string;
/**
* 内置样式
*
* @type {string}
* @memberof AppFormItem2
*/
@Prop() public uiStyle?: string;
/**
* 表单项值规则
*
* @type {string}
* @memberof AppFormItem2
*/
@Prop() public itemRules!: string;
/**
* 值规则数组
*
* @type {any[]}
* @memberof AppFormItem2
*/
public rules: any[] = [];
/**
* 是否必填
*
* @type {boolean}
* @memberof AppFormItem2
*/
public required: boolean = false;
/**
* 表单项值规则监控
*
* @param {*} newVal
* @param {*} oldVal
* @memberof AppFormItem2
*/
@Watch('itemRules')
onItemRulesChange(newVal: any, oldVal: any) {
if (newVal) {
try {
this.rules = [];
const _rules: any[] = JSON.parse(newVal);
this.rules = [..._rules];
this.rules.some((rule: any) => {
if (rule.hasOwnProperty('required')) {
this.required = rule.required;
return true;
}
return false;
});
} catch (error) {
}
}
}
/**
* 计算样式
*
* @readonly
* @type {string[]}
* @memberof AppFormItem2
*/
get classes(): string[] {
return [
'app-form-item2',
Object.is(this.labelPos, 'TOP') ? 'app-form-item-label-top' : ''
];
}
/**
* vue 生命周期
*
* @memberof AppFormItem2
*/
public mounted() {
if (this.itemRules) {
try {
const _rules: any[] = JSON.parse(this.itemRules);
this.rules = [..._rules];
this.rules.some((rule: any) => {
if (rule.hasOwnProperty('required')) {
this.required = rule.required;
return true;
}
return false;
});
} catch (error) {
}
}
}
/**
* 绘制提示框
*
* @returns
* @memberof AppFormItem2
*/
public renderErrorTip() {
const _formitem: any = this.$refs[this.name];
return (
_formitem && _formitem.validateState && Object.is(_formitem.validateState, 'error') ?
<div class='app-error-tip'>
<poptip trigger='hover' placement='left' width={300} word-wrap={true} transfer={true}>
<icon type='ios-information-circle-outline' color='#ed4014' size={20}></icon>
<div slot='content' class='app-form-item-error-info'>
<div class='icon'>
<icon type='ios-information-circle-outline' color='#ed4014' size={20}></icon>
</div>
<div class='contant'>
{_formitem.validateMessage}
</div>
</div>
</poptip>
</div>
: ''
);
}
/**
* 绘制内容
*
* @returns
* @memberof AppFormItem2
*/
public render() {
return (
<form-item
prop={this.name}
error={this.error}
required={this.required}
rules={this.rules}
class={this.classes}
label-width={this.isShowCaption ? !Object.is(this.labelPos, 'TOP') ? this.labelWidth : null : 0}
ref={this.name}>
{
this.isShowCaption && this.labelWidth > 0 ?
<span slot='label'>
{this.isEmptyCaption ? '' : this.caption}
</span>
: ''
}
<div class='app-editor-contant'>
{this.$slots.default}
</div>
{this.renderErrorTip()}
</form-item>
)
}
}
\ No newline at end of file
.form-detail-show {
display: block;
}
.form-detail-hidden {
display: none;
}
.app-form {
height: 100%;
> .ivu-row {
height: 100%;
> .ivu-tabs {
height: 100%;
> .ivu-tabs-content {
height: calc(100% - 50px);
overflow: auto;
> .ivu-tabs-tabpane {
height: 100%;
overflow: auto;
}
}
}
> .el-tabs {
height: 100%;
> .el-tabs__content {
height: calc(100% - 51px);
> .el-tab-pane {
height: 100%;
overflow: auto;
}
}
.el-tabs__header {
.el-tabs__nav-wrap::after {
background-color: var(--app-border-content);
height: 1px;
}
.el-tabs__item {
height: 36px;
}
}
}
}
}
\ No newline at end of file
import { Component, Vue, Prop } from 'vue-property-decorator';
import './app-form.less';
@Component({})
export default class AppForm extends Vue {
/**
* 表单数据对象
*
* @type {*}
* @memberof Form
*/
@Prop() public form?: any;
/**
* 表单名称
*
* @type {string}
* @memberof Form
*/
@Prop() public name?: string;
/**
* 内容绘制
*
* @returns
* @memberof Form
*/
public render() {
return (
<i-form form={this.form}>
<row >
{this.$slots.default}
</row>
</i-form>
);
}
}
\ No newline at end of file
/*** BEGIN:图片上传 ***/
.app-picture-upload {
>div{
display: inline;
}
.el-upload-disabled {
.el-upload {
cursor: not-allowed;
}
}
.el-image {
.image-slot {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
background: #f5f7fa;
color: #909399;
font-size: 30px;
}
}
}
.app-image-upload-model {
.el-image {
width: 100%;
height: 100%;
.image-slot {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 300px;
background: #f5f7fa;
color: #909399;
font-size: 30px;
}
}
}
/*** END:图片上传 ***/
\ No newline at end of file
此差异已折叠。
<script>
export default {
name: 'app-keep-alive',
render: function render() {
let _this = this;
let slot = _this.$slots.default;
let vnode = _this.getFirstComponentChild(slot);
let componentOptions = vnode && vnode.componentOptions;
if (componentOptions) {
// check pattern
let name = _this.getComponentName(componentOptions);
let ref = _this;
let include = ref.include;
let exclude = ref.exclude;
let routerList = ref.routerList;
let route = ref.$route;
if (
// not included
(include && (!name || !_this.matches(include, name))) ||
// excluded
(exclude && name && _this.matches(exclude, name)) ||
(routerList && (!route.fullPath && !_this.matches(routerList, route.fullPath)))
) {
return vnode
}
let ref$1 = _this;
let cache = ref$1.cache;
let keys = ref$1.keys;
let key = vnode.key == null
// same constructor may get registered as different local components
// so cid alone is not enough (#3269)
? componentOptions.Ctor.cid + (componentOptions.tag ? ("::" + (componentOptions.tag)) : '')
: vnode.key;
if (cache[key]) {
vnode.componentInstance = cache[key].componentInstance;
// make current key freshest
_this.remove(keys, key);
keys.push(key);
} else {
cache[key] = vnode;
keys.push(key);
// prune oldest entry
if (_this.max && keys.length > parseInt(_this.max)) {
_this.pruneCacheEntry(cache, keys[0], keys, _this._vnode);
}
}
vnode.data.keepAlive = true;
vnode.data.curPath = route.fullPath;
}
return vnode || (slot && slot[0])
},
props: {
include: [String, RegExp, Array],
exclude: [String, RegExp, Array],
max: [String, Number],
routerList: [Array]
},
data: function(){
return {
_toString: Object.prototype.toString
}
},
created: function () {
this.cache = Object.create(null);
this.keys = [];
},
destroyed: function () {
let _this = this;
for (let key in _this.cache) {
_this.pruneCacheEntry(_this.cache, key, _this.keys);
}
},
watch: {
'include': function (val) {
let _this = this;
_this.pruneCache(function (name) {
return _this.matches(val, name);
});
},
'exclude': function (val) {
let _this = this;
_this.pruneCache(function (name) {
return !_this.matches(val, name);
});
},
'routerList': function(val) {
let _this = this;
_this.pruneCache2(function (name) {
return !_this.matches(val, name);
});
}
},
methods: {
pruneCacheEntry(cache, key, keys, current) {
let cached = cache[key];
if (cached) {
cached.componentInstance.$destroy();
}
cache[key] = null;
this.remove(keys, key);
},
pruneCache(filter) {
let _this = this;
let cache = _this.cache;
let keys = _this.keys;
let _vnode = _this._vnode;
for (let key in cache) {
let cachedNode = cache[key];
if (cachedNode) {
let name = _this.getComponentName(cachedNode.componentOptions);
if (name && !filter(name)) {
_this.pruneCacheEntry(cache, key, keys, _vnode);
}
}
}
},
pruneCache2(filter) {
let _this = this;
let cache = _this.cache;
let keys = _this.keys;
let _vnode = _this._vnode;
for (let key in cache) {
let cachedNode = cache[key];
if (cachedNode) {
let name = cachedNode.data.curPath;
if (name && filter(name)) {
_this.pruneCacheEntry(cache, key, keys, _vnode);
}
}
}
},
matches(pattern, name) {
if (Array.isArray(pattern)) {
return pattern.indexOf(name) > -1
} else if (typeof pattern === 'string') {
return pattern.split(',').indexOf(name) > -1
} else if (this.isRegExp(pattern)) {
return pattern.test(name)
}
/* istanbul ignore next */
return false
},
getComponentName(opts) {
return opts && (opts.Ctor.options.name || opts.tag)
},
getFirstComponentChild(children) {
let _this = this;
if (Array.isArray(children)) {
for (let i = 0; i < children.length; i++) {
let c = children[i];
if (_this.isDef(c) && (_this.isDef(c.componentOptions) || _this.isAsyncPlaceholder(c))) {
return c
}
}
}
},
isAsyncPlaceholder(node) {
return node.isComment && node.asyncFactory
},
isDef(v) {
return v !== undefined && v !== null
},
isRegExp(v) {
return this._toString.call(v) === '[object RegExp]'
},
remove(arr, item) {
if (arr.length) {
let index = arr.indexOf(item);
if (index > -1) {
return arr.splice(index, 1)
}
}
}
}
}
</script>
<style lang="less">
</style>
import { Component, Vue } from 'vue-property-decorator';
import './app-lang.less';
import { localList } from '@locale/local-list';
@Component({})
export default class AppLang extends Vue {
/**
* 本地语言资源
*
* @type {*}
* @memberof AppLang
*/
public localList: any[] = localList;
/**
* 标题
*
* @type {(string | null)}
* @memberof AppLang
*/
public title: string | null = null;
/**
* vue 生命周期
*
* @memberof AppLang
*/
public mounted() {
const lang: string = this.$i18n.locale;
const local: any = this.localList.find((_local: any) => Object.is(_local.type, lang));
this.title = local.name;
}
/**
* 选择语言
*
* @param {*} $evnet
* @memberof AppLang
*/
public selectLang($evnet: any): void {
this.$i18n.locale = $evnet;
const local: any = this.localList.find((_local: any) => Object.is(_local.type, $evnet));
this.title = local.name;
localStorage.setItem('local', $evnet);
}
/**
* 内容绘制
*
* @returns
* @memberof Form
*/
public render() {
return (
<dropdown trigger='click' on-on-click={($event: any) => this.selectLang($event)}>
<span>
{this.title}
<icon size='18' type='md-arrow-dropdown'></icon>
</span>
<dropdown-menu slot='list'>
{
this.localList.map((item: any) => {
return (
<dropdown-item name={item.type} key={`lang-${item.type}`}>{item.name}</dropdown-item>
);
})
}
</dropdown-menu>
</dropdown>
);
}
}
\ No newline at end of file
import { Component, Vue, Prop, Watch } from 'vue-property-decorator';
import './app-mpicker.less';
import { Subject } from 'rxjs';
import { AppModal } from '@/utils';
@Component({})
export default class AppMpicker extends Vue {
/**
* 传入url
*/
@Prop() url?: any;
/**
* 表单数据
*/
@Prop() activeData?: any;
/**
* 是否禁用
*/
@Prop() disabled?: boolean;
/**
* 编辑器参数
*/
@Prop() editorParams?: any;
/**
* 表单项值
*/
@Prop() curvalue?: any;
/**
* 表单项名称
*/
@Prop() name: any;
/**
* 打开对应的选择视图
*/
@Prop() pickupView?: any;
/**
* 当前表单项绑定值key的集合
*/
public value: any;
/**
* 所有操作过的下拉选选项
*/
public items: Array<any> = [];
/**
* 选中项key-value键值对
*
*/
public selectItems: Array<any> = [];
/**
* 监听curvalue值
* @param newVal
* @param val
*/
@Watch('curvalue', { deep: true })
oncurvalueChange(newVal: any, val: any) {
this.value = [];
this.selectItems = [];
if (newVal) {
this.selectItems = JSON.parse(newVal);
this.selectItems.forEach((item: any) => {
this.value.push(item.srfkey);
let index = this.items.findIndex((i) => Object.is(i.value, item.srfkey));
if (index < 0) {
this.items.push({ text: item.srfmajortext, value: item.srfkey });
}
});
}
this.$forceUpdate();
}
/**
* 远程执行搜索
*
* @param {*} query
* @memberof AppMpicker
*/
public onSearch(query: any) {
if (this.url) {
let param: any = {
srfaction: 'itemfetch',
query: query
};
if (this.activeData) {
Object.assign(param, { srfreferdata: this.activeData });
}
this.$http.post(`${this.url}${this.name}/ac`, param).then((data: any) => {
this.items = data.items;
})
}
}
/**
* 下拉选中回调
*
* @param {*} selects
* @memberof AppMpicker
*/
public onSelect(selects: any) {
let val: Array<any> = [];
if (selects.length > 0) {
selects.forEach((select: any) => {
let index = this.items.findIndex((item) => Object.is(item.value, select));
if (index >= 0) {
let item = this.items[index];
val.push({ srfkey: item.value, srfmajortext: item.text });
} else {
index = this.selectItems.findIndex((item: any) => Object.is(item.srfkey, select));
if (index >= 0) {
let item = this.selectItems[index];
val.push(item);
}
}
});
let value = val.length > 0 ? JSON.stringify(val) : '';
this.$emit('formitemvaluechange', { name: this.name, value: value });
}
}
/**
* 移除标签回调
*
* @param {*} tag
* @memberof AppMpicker
*/
public onRemove(tag: any) {
let index = this.selectItems.findIndex((item: any) => Object.is(item.srfkey, tag));
if (index >= 0) {
this.selectItems.splice(index, 1);
let value = this.selectItems.length > 0 ? JSON.stringify(this.selectItems) : '';
this.$emit('formitemvaluechange', { name: this.name, value: value });
}
}
/**
* 打开视图
*
* @returns
* @memberof AppMpicker
*/
public openView() {
if (this.disabled) {
return;
}
let data = { srfparentdata: { srfparentkey: this.activeData.srfkey }, selectedData: [...this.selectItems], };
if (this.pickupView && Object.keys(this.pickupView).length > 0) {
const view = { ...this.pickupView };
const modal: Subject<any> = AppModal.getInstance().openModal(view, data);
modal.subscribe((result: any) => {
if (!result || !Object.is(result.ret, 'OK')) {
return;
}
let selects: Array<any> = [];
if (result.datas && Array.isArray(result.datas)) {
result.datas.forEach((select: any) => {
selects.push({ srfkey: select.srfkey, srfmajortext: select.srfmajortext });
let index = this.items.findIndex((item) => Object.is(item.value, select.srfkey));
if (index < 0) {
this.items.push({ text: select.srfmajortext, value: select.srfkey });
}
});
}
if (this.name && this.activeData) {
let value = selects.length > 0 ? JSON.stringify(selects) : '';
this.$emit('formitemvaluechange', { name: this.name, value: value });
}
})
}
}
/**
* 渲染组件
*
* @returns
* @memberof AppMpicker
*/
public render() {
return (<div>
<div style="position: relative;width: 100%;">
<el-select value={this.value} multiple filterable remote remote-method={this.onSearch} size="small" style="width:100%;" on-change={this.onSelect} on-remove-tag={this.onRemove} disabled={this.disabled}>
{this.items.map((item: any) => {
return <el-option label={item.text} value={item.value}></el-option>
})}
</el-select>
<span style="position: absolute;right: 5px;color: #c0c4cc;top: 0;font-size: 13px;">
<i class="el-icon-search" on-click={this.openView}></i>
</span>
</div>
</div>);
}
}
\ No newline at end of file
.app-picker {
width: 100%;
.el-select {
.el-input__suffix {
right: 20px;
}
}
.text-value {
.el-icon-circle-close {
display: none;
}
}
.text-value:hover {
.el-icon-circle-close {
display: inline-block;
}
}
.ivu-icon-ios-open-outline {
margin-top: -2px;
margin-left: 5px;
font-size: 15px;
}
}
\ No newline at end of file
此差异已折叠。
.app-radio-group {
overflow: auto;
}
\ No newline at end of file
此差异已折叠。
.app-range-editor {
display: flex;
.editor-space {
padding: 0 5px;
font-size: 15px;
}
.ivu-date-picker {
flex-grow: 1;
}
}
\ No newline at end of file
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
.app-header-user {
.user {
font-size: 15px;
cursor: pointer;
margin-right: 10px;
padding: 0 5px;
}
}
\ No newline at end of file
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown 格式
0% or
您添加了 0 到此讨论。请谨慎行事。
先完成此消息的编辑!
想要评论请 注册