This commit is contained in:
caishi 2023-09-21 15:22:01 +08:00
commit e238f9c423
30 changed files with 1807 additions and 74 deletions

372
package-lock.json generated
View File

@ -489,11 +489,21 @@
"resolved": "http://173.15.15.82:8081/repository/npm-all/@tootallnate/once/-/once-1.1.2.tgz",
"integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw=="
},
"@transloadit/prettier-bytes": {
"version": "0.0.7",
"resolved": "https://registry.npmmirror.com/@transloadit/prettier-bytes/-/prettier-bytes-0.0.7.tgz",
"integrity": "sha512-VeJbUb0wEKbcwaSlj5n+LscBl9IPgLPkHVGBkh00cztv6X4L/TJXK58LzFuBKX7/GAfiGhIwH67YTLTlzvIzBA=="
},
"@types/estree": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz",
"integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ=="
},
"@types/event-emitter": {
"version": "0.3.3",
"resolved": "https://registry.npmmirror.com/@types/event-emitter/-/event-emitter-0.3.3.tgz",
"integrity": "sha512-UfnOK1pIxO7P+EgPRZXD9jMpimd8QEFcEZ5R67R1UhGbv4zghU5+NE7U8M8G9H5Jc8FI51rqDWQs6FtUfq2e/Q=="
},
"@types/glob": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz",
@ -663,6 +673,158 @@
}
}
},
"@uppy/companion-client": {
"version": "2.2.2",
"resolved": "https://registry.npmmirror.com/@uppy/companion-client/-/companion-client-2.2.2.tgz",
"integrity": "sha512-5mTp2iq97/mYSisMaBtFRry6PTgZA6SIL7LePteOV5x0/DxKfrZW3DEiQERJmYpHzy7k8johpm2gHnEKto56Og==",
"requires": {
"@uppy/utils": "^4.1.2",
"namespace-emitter": "^2.0.1"
}
},
"@uppy/core": {
"version": "2.3.4",
"resolved": "https://registry.npmmirror.com/@uppy/core/-/core-2.3.4.tgz",
"integrity": "sha512-iWAqppC8FD8mMVqewavCz+TNaet6HPXitmGXpGGREGrakZ4FeuWytVdrelydzTdXx6vVKkOmI2FLztGg73sENQ==",
"requires": {
"@transloadit/prettier-bytes": "0.0.7",
"@uppy/store-default": "^2.1.1",
"@uppy/utils": "^4.1.3",
"lodash.throttle": "^4.1.1",
"mime-match": "^1.0.2",
"namespace-emitter": "^2.0.1",
"nanoid": "^3.1.25",
"preact": "^10.5.13"
}
},
"@uppy/store-default": {
"version": "2.1.1",
"resolved": "https://registry.npmmirror.com/@uppy/store-default/-/store-default-2.1.1.tgz",
"integrity": "sha512-xnpTxvot2SeAwGwbvmJ899ASk5tYXhmZzD/aCFsXePh/v8rNvR2pKlcQUH7cF/y4baUGq3FHO/daKCok/mpKqQ=="
},
"@uppy/utils": {
"version": "4.1.3",
"resolved": "https://registry.npmmirror.com/@uppy/utils/-/utils-4.1.3.tgz",
"integrity": "sha512-nTuMvwWYobnJcytDO3t+D6IkVq/Qs4Xv3vyoEZ+Iaf8gegZP+rEyoaFT2CK5XLRMienPyqRqNbIfRuFaOWSIFw==",
"requires": {
"lodash.throttle": "^4.1.1"
}
},
"@uppy/xhr-upload": {
"version": "2.1.3",
"resolved": "https://registry.npmmirror.com/@uppy/xhr-upload/-/xhr-upload-2.1.3.tgz",
"integrity": "sha512-YWOQ6myBVPs+mhNjfdWsQyMRWUlrDLMoaG7nvf/G6Y3GKZf8AyjFDjvvJ49XWQ+DaZOftGkHmF1uh/DBeGivJQ==",
"requires": {
"@uppy/companion-client": "^2.2.2",
"@uppy/utils": "^4.1.2",
"nanoid": "^3.1.25"
}
},
"@wangeditor/basic-modules": {
"version": "1.1.7",
"resolved": "https://registry.npmmirror.com/@wangeditor/basic-modules/-/basic-modules-1.1.7.tgz",
"integrity": "sha512-cY9CPkLJaqF05STqfpZKWG4LpxTMeGSIIF1fHvfm/mz+JXatCagjdkbxdikOuKYlxDdeqvOeBmsUBItufDLXZg==",
"requires": {
"is-url": "^1.2.4"
}
},
"@wangeditor/code-highlight": {
"version": "1.0.3",
"resolved": "https://registry.npmmirror.com/@wangeditor/code-highlight/-/code-highlight-1.0.3.tgz",
"integrity": "sha512-iazHwO14XpCuIWJNTQTikqUhGKyqj+dUNWJ9288Oym9M2xMVHvnsOmDU2sgUDWVy+pOLojReMPgXCsvvNlOOhw==",
"requires": {
"prismjs": "^1.23.0"
}
},
"@wangeditor/core": {
"version": "1.1.19",
"resolved": "https://registry.npmmirror.com/@wangeditor/core/-/core-1.1.19.tgz",
"integrity": "sha512-KevkB47+7GhVszyYF2pKGKtCSj/YzmClsD03C3zTt+9SR2XWT5T0e3yQqg8baZpcMvkjs1D8Dv4fk8ok/UaS2Q==",
"requires": {
"@types/event-emitter": "^0.3.3",
"event-emitter": "^0.3.5",
"html-void-elements": "^2.0.0",
"i18next": "^20.4.0",
"scroll-into-view-if-needed": "^2.2.28",
"slate-history": "^0.66.0"
},
"dependencies": {
"@babel/runtime": {
"version": "7.22.15",
"resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.22.15.tgz",
"integrity": "sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA==",
"requires": {
"regenerator-runtime": "^0.14.0"
}
},
"i18next": {
"version": "20.6.1",
"resolved": "https://registry.npmmirror.com/i18next/-/i18next-20.6.1.tgz",
"integrity": "sha512-yCMYTMEJ9ihCwEQQ3phLo7I/Pwycf8uAx+sRHwwk5U9Aui/IZYgQRyMqXafQOw5QQ7DM1Z+WyEXWIqSuJHhG2A==",
"requires": {
"@babel/runtime": "^7.12.0"
}
},
"regenerator-runtime": {
"version": "0.14.0",
"resolved": "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz",
"integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA=="
}
}
},
"@wangeditor/editor": {
"version": "5.1.23",
"resolved": "https://registry.npmmirror.com/@wangeditor/editor/-/editor-5.1.23.tgz",
"integrity": "sha512-0RxfeVTuK1tktUaPROnCoFfaHVJpRAIE2zdS0mpP+vq1axVQpLjM8+fCvKzqYIkH0Pg+C+44hJpe3VVroSkEuQ==",
"requires": {
"@uppy/core": "^2.1.1",
"@uppy/xhr-upload": "^2.0.3",
"@wangeditor/basic-modules": "^1.1.7",
"@wangeditor/code-highlight": "^1.0.3",
"@wangeditor/core": "^1.1.19",
"@wangeditor/list-module": "^1.0.5",
"@wangeditor/table-module": "^1.1.4",
"@wangeditor/upload-image-module": "^1.0.2",
"@wangeditor/video-module": "^1.1.4",
"dom7": "^3.0.0",
"is-hotkey": "^0.2.0",
"lodash.camelcase": "^4.3.0",
"lodash.clonedeep": "^4.5.0",
"lodash.debounce": "^4.0.8",
"lodash.foreach": "^4.5.0",
"lodash.isequal": "^4.5.0",
"lodash.throttle": "^4.1.1",
"lodash.toarray": "^4.4.0",
"nanoid": "^3.2.0",
"slate": "^0.72.0",
"snabbdom": "^3.1.0"
}
},
"@wangeditor/editor-for-react": {
"version": "1.0.6",
"resolved": "https://registry.npmmirror.com/@wangeditor/editor-for-react/-/editor-for-react-1.0.6.tgz",
"integrity": "sha512-KJNSfgMr5Blzae3oyaiz20flMKHZHnvsz4bCYQKDCUs/qkvC+xNTnwedlCmhGP187oPWPEypCIYI8Zg6sz0psQ=="
},
"@wangeditor/list-module": {
"version": "1.0.5",
"resolved": "https://registry.npmmirror.com/@wangeditor/list-module/-/list-module-1.0.5.tgz",
"integrity": "sha512-uDuYTP6DVhcYf7mF1pTlmNn5jOb4QtcVhYwSSAkyg09zqxI1qBqsfUnveeDeDqIuptSJhkh81cyxi+MF8sEPOQ=="
},
"@wangeditor/table-module": {
"version": "1.1.4",
"resolved": "https://registry.npmmirror.com/@wangeditor/table-module/-/table-module-1.1.4.tgz",
"integrity": "sha512-5saanU9xuEocxaemGdNi9t8MCDSucnykEC6jtuiT72kt+/Hhh4nERYx1J20OPsTCCdVr7hIyQenFD1iSRkIQ6w=="
},
"@wangeditor/upload-image-module": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/@wangeditor/upload-image-module/-/upload-image-module-1.0.2.tgz",
"integrity": "sha512-z81lk/v71OwPDYeQDxj6cVr81aDP90aFuywb8nPD6eQeECtOymrqRODjpO6VGvCVxVck8nUxBHtbxKtjgcwyiA=="
},
"@wangeditor/video-module": {
"version": "1.1.4",
"resolved": "https://registry.npmmirror.com/@wangeditor/video-module/-/video-module-1.1.4.tgz",
"integrity": "sha512-ZdodDPqKQrgx3IwWu4ZiQmXI8EXZ3hm2/fM6E3t5dB8tCaIGWQZhmqd6P5knfkRAd3z2+YRSRbxOGfoRSp/rLg=="
},
"@webassemblyjs/ast": {
"version": "1.9.0",
"resolved": "http://173.15.15.82:8081/repository/npm-all/@webassemblyjs/ast/-/ast-1.9.0.tgz",
@ -4065,6 +4227,11 @@
"webpack-sources": "^1.0.1"
}
},
"compute-scroll-into-view": {
"version": "1.0.20",
"resolved": "https://registry.npmmirror.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz",
"integrity": "sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg=="
},
"concat": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/concat/-/concat-1.0.3.tgz",
@ -4850,6 +5017,15 @@
"integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=",
"dev": true
},
"d": {
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/d/-/d-1.0.1.tgz",
"integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
"requires": {
"es5-ext": "^0.10.50",
"type": "^1.0.1"
}
},
"d3-color": {
"version": "1.4.1",
"resolved": "http://173.15.15.82:8081/repository/npm-all/d3-color/-/d3-color-1.4.1.tgz",
@ -5397,6 +5573,14 @@
"resolved": "http://173.15.15.82:8081/repository/npm-all/dom-walk/-/dom-walk-0.1.2.tgz",
"integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w=="
},
"dom7": {
"version": "3.0.0",
"resolved": "https://registry.npmmirror.com/dom7/-/dom7-3.0.0.tgz",
"integrity": "sha512-oNlcUdHsC4zb7Msx7JN3K0Nro1dzJ48knvBOnDPKJ2GV9wl1i5vydJZUSyOfrkKFDZEud/jBsTk92S/VGSAe/g==",
"requires": {
"ssr-window": "^3.0.0-alpha.1"
}
},
"domain-browser": {
"version": "1.2.0",
"resolved": "http://173.15.15.82:8081/repository/npm-all/domain-browser/-/domain-browser-1.2.0.tgz",
@ -5749,11 +5933,40 @@
"is-symbol": "^1.0.2"
}
},
"es5-ext": {
"version": "0.10.62",
"resolved": "https://registry.npmmirror.com/es5-ext/-/es5-ext-0.10.62.tgz",
"integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==",
"requires": {
"es6-iterator": "^2.0.3",
"es6-symbol": "^3.1.3",
"next-tick": "^1.1.0"
}
},
"es6-iterator": {
"version": "2.0.3",
"resolved": "https://registry.npmmirror.com/es6-iterator/-/es6-iterator-2.0.3.tgz",
"integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==",
"requires": {
"d": "1",
"es5-ext": "^0.10.35",
"es6-symbol": "^3.1.1"
}
},
"es6-promise": {
"version": "4.2.8",
"resolved": "http://173.15.15.82:8081/repository/npm-all/es6-promise/-/es6-promise-4.2.8.tgz",
"integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w=="
},
"es6-symbol": {
"version": "3.1.3",
"resolved": "https://registry.npmmirror.com/es6-symbol/-/es6-symbol-3.1.3.tgz",
"integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==",
"requires": {
"d": "^1.0.1",
"ext": "^1.1.2"
}
},
"escalade": {
"version": "3.1.1",
"resolved": "http://173.15.15.82:8081/repository/npm-all/escalade/-/escalade-3.1.1.tgz",
@ -6405,6 +6618,15 @@
"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=",
"dev": true
},
"event-emitter": {
"version": "0.3.5",
"resolved": "https://registry.npmmirror.com/event-emitter/-/event-emitter-0.3.5.tgz",
"integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==",
"requires": {
"d": "1",
"es5-ext": "~0.10.14"
}
},
"eventemitter3": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-2.0.3.tgz",
@ -6566,6 +6788,21 @@
}
}
},
"ext": {
"version": "1.7.0",
"resolved": "https://registry.npmmirror.com/ext/-/ext-1.7.0.tgz",
"integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==",
"requires": {
"type": "^2.7.2"
},
"dependencies": {
"type": {
"version": "2.7.2",
"resolved": "https://registry.npmmirror.com/type/-/type-2.7.2.tgz",
"integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw=="
}
}
},
"extend": {
"version": "3.0.2",
"resolved": "http://173.15.15.82:8081/repository/npm-all/extend/-/extend-3.0.2.tgz",
@ -8702,6 +8939,11 @@
"void-elements": "3.1.0"
}
},
"html-void-elements": {
"version": "2.0.1",
"resolved": "https://registry.npmmirror.com/html-void-elements/-/html-void-elements-2.0.1.tgz",
"integrity": "sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A=="
},
"html-webpack-plugin": {
"version": "4.5.2",
"resolved": "http://173.15.15.82:8081/repository/npm-all/html-webpack-plugin/-/html-webpack-plugin-4.5.2.tgz",
@ -9755,6 +9997,11 @@
"is-extglob": "^1.0.0"
}
},
"is-hotkey": {
"version": "0.2.0",
"resolved": "https://registry.npmmirror.com/is-hotkey/-/is-hotkey-0.2.0.tgz",
"integrity": "sha512-UknnZK4RakDmTgz4PI1wIph5yxSs/mvChWs9ifnlXsKuXgWmOkY/hAE0H/k2MIqH0RlRye0i1oC07MCRSD28Mw=="
},
"is-in-browser": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz",
@ -9945,6 +10192,11 @@
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
},
"is-url": {
"version": "1.2.4",
"resolved": "https://registry.npmmirror.com/is-url/-/is-url-1.2.4.tgz",
"integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww=="
},
"is-utf8": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
@ -10946,6 +11198,16 @@
"integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=",
"dev": true
},
"lodash.camelcase": {
"version": "4.3.0",
"resolved": "https://registry.npmmirror.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
"integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="
},
"lodash.clonedeep": {
"version": "4.5.0",
"resolved": "https://registry.npmmirror.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
"integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ=="
},
"lodash.cond": {
"version": "4.5.2",
"resolved": "https://registry.npmjs.org/lodash.cond/-/lodash.cond-4.5.2.tgz",
@ -10975,6 +11237,11 @@
"integrity": "sha512-ff3BX/tSioo+XojX4MOsOMhJw0nZoUEF011LX8g8d3gvjVbxd89cCio4BCXronjxcTUIJUoqKEUA+n4CqvvRPw==",
"dev": true
},
"lodash.foreach": {
"version": "4.5.0",
"resolved": "https://registry.npmmirror.com/lodash.foreach/-/lodash.foreach-4.5.0.tgz",
"integrity": "sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ=="
},
"lodash.isequal": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
@ -11010,6 +11277,11 @@
"resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
"integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ="
},
"lodash.toarray": {
"version": "4.4.0",
"resolved": "https://registry.npmmirror.com/lodash.toarray/-/lodash.toarray-4.4.0.tgz",
"integrity": "sha512-QyffEA3i5dma5q2490+SgCvDN0pXLmRGSyAANuVi0HQ01Pkfr9fuoKQW8wm1wGBnJITs/mS7wQvS6VshUEBFCw=="
},
"lodash.uniq": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
@ -11340,6 +11612,14 @@
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
},
"mime-match": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/mime-match/-/mime-match-1.0.2.tgz",
"integrity": "sha512-VXp/ugGDVh3eCLOBCiHZMYWQaTNUHv2IJrut+yXA6+JbLPXHglHwfS/5A5L0ll+jkCY7fIzRJcH6OIunF+c6Cg==",
"requires": {
"wildcard": "^1.1.0"
}
},
"mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
@ -11576,11 +11856,21 @@
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
"integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s="
},
"namespace-emitter": {
"version": "2.0.1",
"resolved": "https://registry.npmmirror.com/namespace-emitter/-/namespace-emitter-2.0.1.tgz",
"integrity": "sha512-N/sMKHniSDJBjfrkbS/tpkPj4RAbvW3mr8UAzvlMHyun93XEm83IAvhWtJVHo+RHn/oO8Job5YN4b+wRjSVp5g=="
},
"nan": {
"version": "2.17.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz",
"integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ=="
},
"nanoid": {
"version": "3.3.6",
"resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.6.tgz",
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA=="
},
"nanomatch": {
"version": "1.2.13",
"resolved": "http://173.15.15.82:8081/repository/npm-all/nanomatch/-/nanomatch-1.2.13.tgz",
@ -11638,6 +11928,11 @@
"resolved": "http://173.15.15.82:8081/repository/npm-all/neo-async/-/neo-async-2.6.2.tgz",
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="
},
"next-tick": {
"version": "1.1.0",
"resolved": "https://registry.npmmirror.com/next-tick/-/next-tick-1.1.0.tgz",
"integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ=="
},
"nice-try": {
"version": "1.0.5",
"resolved": "http://173.15.15.82:8081/repository/npm-all/nice-try/-/nice-try-1.0.5.tgz",
@ -13561,6 +13856,11 @@
"resolved": "http://173.15.15.82:8081/repository/npm-all/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
"integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ=="
},
"preact": {
"version": "10.17.1",
"resolved": "https://registry.npmmirror.com/preact/-/preact-10.17.1.tgz",
"integrity": "sha512-X9BODrvQ4Ekwv9GURm9AKAGaomqXmip7NQTZgY7gcNmr7XE83adOMJvd3N42id1tMFU7ojiynRsYnY6/BRFxLA=="
},
"prelude-ls": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
@ -13601,6 +13901,11 @@
"ansi-styles": "^3.0.0"
}
},
"prismjs": {
"version": "1.29.0",
"resolved": "https://registry.npmmirror.com/prismjs/-/prismjs-1.29.0.tgz",
"integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q=="
},
"private": {
"version": "0.1.8",
"resolved": "http://173.15.15.82:8081/repository/npm-all/private/-/private-0.1.8.tgz",
@ -16355,7 +16660,7 @@
},
"sass-loader": {
"version": "7.3.1",
"resolved": "https://registry.npmmirror.com/sass-loader/-/sass-loader-7.3.1.tgz",
"resolved": "http://173.15.15.82:8081/repository/npm-all/sass-loader/-/sass-loader-7.3.1.tgz",
"integrity": "sha512-tuU7+zm0pTCynKYHpdqaPpe+MMTQ76I9TPZ7i4/5dZsigE350shQWe5EZNl5dBidM49TPET75tNqRbcsUZWeNA==",
"dev": true,
"requires": {
@ -16521,6 +16826,14 @@
"resolved": "https://registry.npmjs.org/scroll-into-view/-/scroll-into-view-1.16.2.tgz",
"integrity": "sha512-vyTE0i27o6eldt9xinjHec41Dw05y+faoI+s2zNKJAVOdbA5M2XZrYq/obJ8E+QDQulJ2gDjgui9w9m9RZSRng=="
},
"scroll-into-view-if-needed": {
"version": "2.2.31",
"resolved": "https://registry.npmmirror.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.31.tgz",
"integrity": "sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==",
"requires": {
"compute-scroll-into-view": "^1.0.20"
}
},
"scrollama": {
"version": "3.2.0",
"resolved": "https://registry.npmmirror.com/scrollama/-/scrollama-3.2.0.tgz",
@ -17159,6 +17472,43 @@
"resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
"integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU="
},
"slate": {
"version": "0.72.8",
"resolved": "https://registry.npmmirror.com/slate/-/slate-0.72.8.tgz",
"integrity": "sha512-/nJwTswQgnRurpK+bGJFH1oM7naD5qDmHd89JyiKNT2oOKD8marW0QSBtuFnwEbL5aGCS8AmrhXQgNOsn4osAw==",
"requires": {
"immer": "^9.0.6",
"is-plain-object": "^5.0.0",
"tiny-warning": "^1.0.3"
},
"dependencies": {
"immer": {
"version": "9.0.21",
"resolved": "https://registry.npmmirror.com/immer/-/immer-9.0.21.tgz",
"integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA=="
},
"is-plain-object": {
"version": "5.0.0",
"resolved": "https://registry.npmmirror.com/is-plain-object/-/is-plain-object-5.0.0.tgz",
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="
}
}
},
"slate-history": {
"version": "0.66.0",
"resolved": "https://registry.npmmirror.com/slate-history/-/slate-history-0.66.0.tgz",
"integrity": "sha512-6MWpxGQZiMvSINlCbMW43E2YBSVMCMCIwQfBzGssjWw4kb0qfvj0pIdblWNRQZD0hR6WHP+dHHgGSeVdMWzfng==",
"requires": {
"is-plain-object": "^5.0.0"
},
"dependencies": {
"is-plain-object": {
"version": "5.0.0",
"resolved": "https://registry.npmmirror.com/is-plain-object/-/is-plain-object-5.0.0.tgz",
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="
}
}
},
"slice-ansi": {
"version": "1.0.0",
"resolved": "http://173.15.15.82:8081/repository/npm-all/slice-ansi/-/slice-ansi-1.0.0.tgz",
@ -17181,6 +17531,11 @@
"resolved": "http://173.15.15.82:8081/repository/npm-all/slick-carousel/-/slick-carousel-1.8.1.tgz",
"integrity": "sha512-XB9Ftrf2EEKfzoQXt3Nitrt/IPbT+f1fgqBdoxO3W/+JYvtEOW6EgxnWfr9GH6nmULv7Y2tPmEX3koxThVmebA=="
},
"snabbdom": {
"version": "3.5.1",
"resolved": "https://registry.npmmirror.com/snabbdom/-/snabbdom-3.5.1.tgz",
"integrity": "sha512-wHMNIOjkm/YNE5EM3RCbr/+DVgPg6AqQAX1eOxO46zYNvCXjKP5Y865tqQj3EXnaMBjkxmQA5jFuDpDK/dbfiA=="
},
"snapdragon": {
"version": "0.8.2",
"resolved": "http://173.15.15.82:8081/repository/npm-all/snapdragon/-/snapdragon-0.8.2.tgz",
@ -17514,6 +17869,11 @@
"tweetnacl": "~0.14.0"
}
},
"ssr-window": {
"version": "3.0.0",
"resolved": "https://registry.npmmirror.com/ssr-window/-/ssr-window-3.0.0.tgz",
"integrity": "sha512-q+8UfWDg9Itrg0yWK7oe5p/XRCJpJF9OBtXfOPgSJl+u3Xd5KI328RUEvUqSMVM9CiQUEf1QdBzJMkYGErj9QA=="
},
"ssri": {
"version": "5.3.0",
"resolved": "http://173.15.15.82:8081/repository/npm-all/ssri/-/ssri-5.3.0.tgz",
@ -18557,6 +18917,11 @@
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
},
"type": {
"version": "1.2.0",
"resolved": "https://registry.npmmirror.com/type/-/type-1.2.0.tgz",
"integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg=="
},
"type-check": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
@ -20760,6 +21125,11 @@
}
}
},
"wildcard": {
"version": "1.1.2",
"resolved": "https://registry.npmmirror.com/wildcard/-/wildcard-1.1.2.tgz",
"integrity": "sha512-DXukZJxpHA8LuotRwL0pP1+rS6CS7FF2qStDDE1C7DDg2rLud2PXRMuEDYIPhgEezwnlHNL4c+N6MfMTjCGTng=="
},
"window-size": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz",

View File

@ -5,6 +5,8 @@
"dependencies": {
"@monaco-editor/react": "^2.3.0",
"@novnc/novnc": "^1.1.0",
"@wangeditor/editor": "^5.1.23",
"@wangeditor/editor-for-react": "^1.0.6",
"actioncable": "^5.2.4-3",
"ahooks": "^2.10.14",
"antd": "^3.26.15",

View File

@ -7,7 +7,7 @@ export {
getImageUrl as getImageUrl,getImageUrlAbsolute as getImageUrlAbsolute,getImage as getImage, getmyUrl as getmyUrl, getRandomNumber as getRandomNumber, getUrl as getUrl, getZoneUrl as getZoneUrl, publicSearchs as publicSearchs, getRandomcode as getRandomcode, getUrlmys as getUrlmys, getUrl2 as getUrl2, setImagesUrl as setImagesUrl
, getUploadActionUrl as getUploadActionUrl, getUploadActionUrltwo as getUploadActionUrltwo, getUploadActionUrlthree as getUploadActionUrlthree, getUploadActionUrlOfAuth as getUploadActionUrlOfAuth
, getTaskUrlById as getTaskUrlById, TEST_HOST, htmlEncode as htmlEncode, getupload_git_file as getupload_git_file, getcdnImageUrl as getcdnImageUrl,
turnbar,returnbar,setSeoMeta as setSeoMeta , IsPC as IsPC
turnbar,returnbar,setSeoMeta as setSeoMeta , IsPC as IsPC, addMeta as addMeta
} from './UrlTool';
export { setmiyah as setmiyah } from './Component';

View File

@ -0,0 +1,124 @@
import React, { useState, useEffect } from 'react';
import { Editor, Toolbar } from '@wangeditor/editor-for-react';
import '@wangeditor/editor/dist/css/style.css';
import cookie from 'react-cookies';
import { message, Spin } from 'antd';
import axios from 'axios';
//
function MyEditor(props) {
const {value, setValue, uploadUrl, videoUploadUrl} = props;
// editor
const [editor, setEditor] = useState(null);
const [loading, setLoading] = useState(false);
// ajax html
useEffect(() => {
if(value && setValue){
setValue(value);
}
}, []);
//
const toolbarConfig = {};
//
toolbarConfig.excludeKeys = [
'todo'
]
//
const editorConfig = {
placeholder: '请输入内容...',
MENU_CONF:{
uploadImage:{
server: uploadUrl,
headers: {
Authorization: cookie.load('autologin_trustie')
},
withCredentials: true,
fieldName: "file",
maxFileSize: 20 * 1024 * 1024,
allowedFileTypes: ["image/jpeg", "image/png", "image/gif", "image/webp", "image/svg+xml", "image/bmp"],
customInsert(res, insertFn){
const {url} = res;
insertFn(url, "图片", url);
},
onBeforeUpload(file){
const {type, name} = Object.values(file)[0];
const typeRange = ["image/jpeg", "image/png", "image/gif", "image/webp", "image/svg+xml", "image/bmp"];
const suffix = name && name.split(".")[1];
const isType = typeRange.indexOf(type) !== -1 && suffix !== "tiff";
if(!isType){
message.error("只能上传jpg、jpeg、webp、png、svg、gif、bmp格式的图片!")
return false;
}
return file;
},
onError(file, err) {
message.error(`${file.name} 上传出错, ${err}` )
},
},
uploadVideo:{
//
async customUpload(file, insertFn){
if (!file.type.includes("video")) {
return message.error("请上传视频格式的文件!");
} else if (file.size / 1024 / 1024 > 200) {
return message.error("请上传200M以内的文件");
}
const formData = new FormData();
formData.append("file", file);
setLoading(true);
axios.post(videoUploadUrl || uploadUrl, formData, {headers: {Authorization: cookie.load('autologin_trustie')}}).then(res=>{
setLoading(false);
if(res && res.data && res.data.code === 200){
insertFn(res.data.url)
}else{
message.error(res && res.data && res.data.msg)
}
})
}
}
}
};
// editor
useEffect(() => {
return () => {
if (editor === null) return;
editor.destroy();
setEditor(null);
};
}, [editor]);
const editorBoxClass = {
border: '1px solid #ccc',
zIndex: 100,
'video': {
maxWidth: '100%'
}
}
return (
<div style={editorBoxClass}>
<Spin spinning={loading} tip="上传中,请耐心等待">
<Toolbar
editor={editor}
defaultConfig={toolbarConfig}
mode="default"
style={{ borderBottom: '1px solid #ccc' }}
/>
<Editor
defaultConfig={editorConfig}
value={value}
onCreated={setEditor}
onChange={(editor) => setValue && setValue(editor.getHtml())}
mode="default"
style={{ height: '500px', overflowY: 'hidden' }}
/>
</Spin>
</div>
);
}
export default MyEditor;

View File

@ -5,7 +5,7 @@ import { postCreateZone } from '../api';
const { TextArea } = Input;
const phonereg = /^([1][3456789])\d{9}$/
const idenReg = /^[a-zA-Z][a-zA-Z0-9-_]{0,18}[a-zA-Z]+$/g
const idenReg = /^[a-zA-Z][a-zA-Z0-9-_]{0,18}[a-zA-Z]$/g
function Apply(props){
const { form } = props;
const { getFieldDecorator , validateFields } = form;
@ -39,12 +39,12 @@ function Apply(props){
}
function checkIndentity(rule, value, callback){
if(value && !idenReg.test(value)){
callback("专区标识长度2-20只能以字母开头结尾可包含数字、下划线、中划线");
}
callback();
}
// function checkIndentity(rule, value, callback){
// if(value && !idenReg.test(value)){
// callback("2-20线线");
// }
// callback();
// }
return(
<div className="applyBox">
@ -93,8 +93,8 @@ function Apply(props){
{getFieldDecorator("key",{
rules:[
{ required: true,message:"请输入专区域名标识" },
{ validator: checkIndentity }
]
{ pattern: /^[a-zA-Z][a-zA-Z0-9_-]{0,18}[a-zA-Z]$/, message: "长度2-20只能包含数字、字母、下划线、中划线必须以字母开头结尾"},
]
})(
<Input placeholder="请输入专区域名标识" maxLength={20} style={{height:"36px"}}/>
)}

View File

@ -1,7 +1,7 @@
import React , { useState , useEffect } from 'react';
import { Menu , Spin , Skeleton } from 'antd';
import { Menu , Spin , Skeleton, Button, Dropdown } from 'antd';
import Hot from '../Component/hot';
import { Box , LongWidth } from '../../Component/layout';
import { Box , FlexAJ, LongWidth } from '../../Component/layout';
import { Link } from 'react-router-dom';
import Lists from './newsList';
import guideArrow from '../img/guideArrow.png';
@ -24,7 +24,18 @@ function Main(props){
const [ isSpin , setIsSpin ] = useState(true);
const [ newCateId , setNewCateId ] = useState(undefined);
const { deptId , cateId } = props.match.params;
const { id, temp } = props;
const { id, temp, role, history } = props;
const menu = (
<Menu>
<Menu.Item>
<a onClick={()=>{history.push(`/zone/${deptId}/news/add?type=richEditor`)}}>富文本编辑器</a>
</Menu.Item>
<Menu.Item>
<a onClick={()=>{history.push(`/zone/${deptId}/news/add?type=mdEditor`)}}>MD编辑器</a>
</Menu.Item>
</Menu>
);
useEffect(()=>{
@ -34,7 +45,7 @@ function Main(props){
getMainList();
} else {
getCateList();
}
}
getHotList();
}
},[id])
@ -109,7 +120,17 @@ function Main(props){
<div>
<div className="main_content">
<div className="boxmain">
<p className="in_title">{ tempConfig[temp].mainTitle }</p>
<div className='titleButBox'>
<p className="in_title">{tempConfig[temp].mainTitle}</p>
{role && role.role !== "None" && <div className='createButs'>
{role.role === "Member" && <Button type="primary" ghost className='mr20'>
<Link to={`/zone/${deptId}/news/self`}>我的文章</Link>
</Button>}
{role.role === "Member" ? <Dropdown overlay={menu}>
<Button icon='plus' type="primary" ghost>新建</Button>
</Dropdown> : <Button type="primary" ghost onClick={()=>{window.open(role.docManageUrl)}}>管理资讯</Button>}
</div>}
</div>
{
mainList && mainList.length>0 &&
(

View File

@ -0,0 +1,175 @@
import React,{ useState , useEffect } from 'react';
import { Breadcrumb, Button, Form, Input, message, Select } from 'antd';
import { getZoneUrl } from 'educoder';
import MdEditor from '../../../modules/tpm/challengesnew/tpm-md-editor';
import RichEditor from '../../Component/RichEditor';
import UploadImage from '../../Team/Component/UploadImage';
import { tempConfig } from '../tempInfo';
import '../index.scss';
import { Base64 } from 'js-base64';
import { addNewsByDirId, getDirListById, getNewsDetailByAu, updateDoc } from '../api';
import { httpUrl } from '../fetch';
function NewsCreate(props){
const {history, id} = props;
const temp = props.temp;
const { getFieldDecorator, validateFields , setFieldsValue, setFields } = props.form;
const { deptId, id: newsId } = props.match.params;
const pathname = props.location.pathname;
const [type, setType] = useState(new URLSearchParams(props.location.search.substring(1)).get('type'));
const [value, setValue] = useState(undefined);
const [imageUrl, setImageUrl] = useState(undefined)
const [dirList, setDirList] = useState(undefined);
const [loading, setLoading] = useState(false);
const [isEdit, setIsEdit] = useState(false);
const layout = {
labelCol: { span: 2 },
wrapperCol: { span: 14 },
};
useEffect(()=>{
id && getDircList();
},[id])
useEffect(()=>{
if(pathname){
if(pathname.endsWith("/edit")){
setIsEdit(true);
getNewsDetail();
}else{
setIsEdit(false);
}
}
},[pathname])
function getDircList(){
getDirListById(id).then(res=>{
if(res){
setDirList(res.data.rows);
}
})
}
function getNewsDetail() {
getNewsDetailByAu(newsId).then(res=>{
if(res && res.data){
const {name, summary, cmsDir, content, headImg, editorType} = res.data.data;
setType(editorType === "rich_editor" ? 'richEditor' : 'mdEditor')
setFieldsValue({
name,
summary,
dirId: cmsDir && cmsDir.id,
content: Base64.decode(content),
headImg
});
setImageUrl(headImg);
setValue(Base64.decode(content));
}
})
}
//
function submit(e){
e.preventDefault();
validateFields((err, fieldsValue)=>{
const hasContent = type === "richEditor" && fieldsValue.content === "<p><br></p>"
if(err || hasContent){
hasContent && setFields({content: {value:fieldsValue.content,errors:[new Error('请输入内容!')]}});
return;
}
setLoading(true);
const params = {
...fieldsValue,
editorType: type === "richEditor" ? "rich_editor" : "markdown_editor",
headImg: imageUrl,
content: Base64.encode(fieldsValue.content)
}
if(isEdit){
delete params.editorType;
return updateDoc(newsId, params).then(res=>{
const {data:{code, msg}} = res;
setLoading(false);
if(code === 200){
message.success("更新成功");
history.push(`/zone/${deptId}/news/self`);
}else{
message.error(msg || '更新失败,请联系管理员!')
}
})
}
addNewsByDirId(fieldsValue.dirId, params).then(res=>{
const {data:{code, msg}} = res;
setLoading(false);
if(code === 200){
message.success("新增成功");
history.push(`/zone/${deptId}/news/self`);
}else{
message.error(msg || '新增失败,请联系管理员!')
}
})
})
}
return(
<div className='boxmain pt30 newsCreateBox pb100'>
<Breadcrumb separator=">">
<Breadcrumb.Item href={`/zone/${deptId}/news`}>{tempConfig[temp].mainTitle}</Breadcrumb.Item>
<Breadcrumb.Item>{isEdit ? '编辑' : '新建'}文章</Breadcrumb.Item>
</Breadcrumb>
<div className='formBox'>
<Form {...layout} onSubmit={submit}>
<Form.Item label="标题">
{getFieldDecorator("name", {
rules:[{ required:true,message:"请输入文章标题!" },
{type: 'string', max: 200, message: "最大长度200"},
{pattern: /^[^<>[\]/\\]+$/, message: "不能输入特殊字符:< > [ ] / \\"}]
})(
<Input placeholder="请输入文章标题" maxLength={ 200 } width="220px"/>
)}
</Form.Item>
<Form.Item label="概览">
{getFieldDecorator("summary", {
rules:[{ required:true,message:"请输入概览!" },
{type: 'string', max: 200, message: "最大长度200"}]
})(
<Input.TextArea placeholder="请输入概览" maxLength={ 200 } width="220px"/>
)}
</Form.Item>
<Form.Item label="栏目">
{getFieldDecorator("dirId", {
rules:[{ required:true,message:"请选择文章所属栏目!" }]
})(
<Select placeholder="请选择文章所属栏目">
{dirList && dirList.map(item=>{
return <Select.Option key={item.id} value={item.id}>{item.name}</Select.Option>
})}
</Select>
)}
</Form.Item>
<Form.Item label="内容" wrapperCol={{span: 21}}>
{getFieldDecorator("content",{
rules:[{required:true,message:"请输入内容!"}],
})(
type === "richEditor" ? <RichEditor uploadUrl={`${httpUrl}/file/common/upload`} videoUploadUrl={`${httpUrl}/file/common/upload?type=cms`} setValue={(value)=>{setFieldsValue({"content": value})}}/> : <MdEditor
placeholder={"请输入详细介绍"}
height={500}
mdID={"order-new-description"}
initValue={value}
onChange={(value)=>{setFieldsValue({"content": value})}}
imageExpand={false}
></MdEditor>
)}
</Form.Item>
<Form.Item label="首图" extra="建议图片比例宽为32上传jpg、jpeg、webp、png、svg、gif、bmp格式的图片">
<UploadImage maxSize={ 5 } getImageUrl={ (url) => setImageUrl(url) } url={ imageUrl ? imageUrl : undefined} action={ getZoneUrl(`/api/cms/common/upload`) } />
</Form.Item>
<Form.Item wrapperCol={{ offset: 2 }}>
<Button className='mr20 themeBut' onClick={()=>{history.go(-1)}}>取消</Button>
<Button type="primary" htmlType="submit" loading={loading} className='themeBut'>提交</Button>
</Form.Item>
</Form>
</div>
</div>
)
}
export default Form.create()(NewsCreate);

View File

@ -7,7 +7,7 @@ import { getNewsDetail } from '../api';
import { IsPC } from 'educoder';
import { tempConfig } from '../tempInfo';
import Acce from '../Component/mobile/accessory';
import { addMeta, setSeoMeta } from 'educoder';
function NewsDetail(props){
@ -44,6 +44,21 @@ function NewsDetail(props){
}
},[id])
useEffect(()=>{
//
if(detail){
const { name, cmsDir, summary} = detail;
document.title = `${ name }/${ cmsDir.name }`;
addMeta('Keywords', `${ name },${ cmsDir.name },${ summary }`);
}
return componentWillUnmount
}, [detail])
function componentWillUnmount() {
document.title= zonedetail.name;
setSeoMeta(`${zonedetail.name},`, zonedetail.name, zonedetail.subTitle, `/zone/${deptId}`)
}
function getDetails(){
setIsSpin(true)
getNewsDetail(id).then(result=>{

View File

@ -18,8 +18,8 @@ function SelfList(props){
const [ visible ,setVisible ] = useState(false);
const [ deleId , setDeleId] = useState(undefined);
const pathname = props.location.pathname;
const { deptId} = props.match.params;
const { id , temp } = props;
const { deptId } = props.match.params;
const limit = 15;
useEffect(()=>{
@ -141,7 +141,7 @@ function SelfList(props){
<span><i className="iconfont icon-a-31shijian mr5 font-15"></i>{moment(i.createTime).format("YYYY/MM/DD")}</span>
</span>
<span className="s-info-right">
<a href="" style={{color:"#466aff"}}><i className="iconfont icon-a-bianji12 mr5 font-14"></i>编辑</a>
<a href={`/zone/${deptId}/${source ? 'source' : 'news'}/${i.id}/edit`} style={{color:"#466aff"}}><i className="iconfont icon-a-bianji12 mr5 font-14"></i>编辑</a>
<a style={{color:"#d81017",marginLeft:"25px"}}onClick={()=>{setVisible(true);setDeleId(i.id)}}><i className="iconfont icon-fuzhi-shanchu mr5 font-14"></i>删除</a>
</span>
</div>

View File

@ -1,5 +1,5 @@
import React , { useEffect , useState } from 'react';
import { Input , Pagination, Spin, Tag } from 'antd';
import { Button, Input , Pagination, Spin, Tag } from 'antd';
import SourceIcon from '../img/sourceIcon.png';
import { Link } from 'react-router-dom';
import axios from 'axios';
@ -23,8 +23,7 @@ function Source(props){
const [ search , setSearch ] = useState(undefined);
const [ isSpin , setIsSpin ] = useState(true);
const limit = 20;
const { id , temp } = props;
const { id , temp, history, role } = props;
useEffect(()=>{
id && getLists();
@ -70,12 +69,20 @@ function Source(props){
setPage(1);
}
function addSource(){
if(role && role.role === "Manager"){
window.open(role.resourceManageUrl);
}else{
history.push(`/zone/${deptId}/source/add`)
}
}
return(
<div className={`${temp}_source_box`}>
<div className="source_h">
<p className="in_title">资源发布</p>
<div style={{marginTop:"30px",textAlign:"center"}}>
<Search
<div style={{marginTop:"30px",textAlign:"center"}} className='titleButBox'>
<Search
placeholder="请输入资源名称"
onSearch={onSourceSearch}
style={{width:'645px',borderColor:"#fff",boxShadow:"0px 0px 10px rgba(61, 85, 183, 0.1)"}}
@ -84,6 +91,12 @@ function Source(props){
allowClear
enterButton={temp === "zone" ? <span><i className="iconfont icon-sousuo5 font-15"/>搜索</span> :undefined}
/>
{role && role.role !== "None" && <div className='createButs'>
{role.role === "Member" && <Button size='large' type="primary" ghost className='mr20'>
<Link to={`/zone/${deptId}/source/self`}>我的资源</Link>
</Button>}
<Button size='large' icon={role.role === "Member" && 'plus'} type="primary" ghost onClick={addSource}>{role.role === "Member" ? '新建' : '管理资源'}</Button>
</div>}
</div>
</div>
<div className="sources">

View File

@ -0,0 +1,235 @@
import React,{ useState , useEffect } from 'react';
import { Breadcrumb, Button, Form, Icon, Input, message, Select, Upload } from 'antd';
import { getZoneUrl } from 'educoder';
import '../index.scss';
import { Link } from 'react-router-dom';
import { getTypeByFileId, getSourceZoneList, addResource, getSourceDetailByAu, updateMyResource } from '../api';
function SourceCreate(props){
const {history, id} = props;
const { getFieldDecorator, validateFields , setFieldsValue, setFields } = props.form;
const { deptId, sourceid} = props.match.params;
const pathname = props.location.pathname;
const [ zoneList , setZoneList ] = useState(undefined);
const [files, setFiles] = useState([]);
const [loadingBut, setLoadingBut] = useState(false);
const [isEdit, setIsEdit] = useState(false);
const layout = {
labelCol: { span: 2 },
wrapperCol: { span: 14 },
};
useEffect(()=>{
id && getZoneList();
},[id])
useEffect(()=>{
if(pathname){
if(pathname.endsWith("/edit")){
setIsEdit(true);
getSourceDetail();
}else{
setIsEdit(false);
}
}
},[pathname])
function getSourceDetail() {
getSourceDetailByAu(sourceid).then(res=>{
if(res && res.data){
const {name, domainId, summary, fileList} = res.data.data;
const fileMap = fileList.map(item=>{
const {fileId, fileSizeInfo, fileOriginName, zoneResourceType: {id, name}} = item;
return {
uid: fileId,
status: "done",
response: {fileId: fileId, fileSize: fileSizeInfo},
name: fileOriginName,
zoneResourceType:{id, name}
}
})
setFiles(fileMap);
setFieldsValue({
name,
domainId,
summary,
fileList: fileMap
});
}
})
}
function getZoneList(){
getSourceZoneList(id).then(response=>{
if(response && response.data){
setZoneList(response.data.rows);
}
}).catch(error=>{})
}
//
function submit(e){
e.preventDefault();
validateFields((err, fieldsValue)=>{
if(err || !files.length){
!files.length && setFields({fileList: {value:undefined,errors:[new Error('请上传资源附件!')]}});
return;
}
const fileIds = files.map(item=>{return item.response.fileId}).toString();
const params = {
...fieldsValue,
zoneId: id,
fileIds
}
delete params.fileList;
if(isEdit){
delete params.zoneId;
params.id= parseInt(sourceid, 10);
updateMyResource(params).then((res)=>{
const {data:{code, msg}} = res;
if(code === 200){
message.success("编辑成功");
history.push(`/zone/${deptId}/source/self`);
}else{
message.error(msg || '编辑失败,请联系管理员!')
}
})
return;
}
addResource(params).then((res)=>{
const {data:{code, msg}} = res;
if(code === 200){
message.success("新增成功");
history.push(`/zone/${deptId}/source/self`);
}else{
message.error(msg || '新增失败,请联系管理员!')
}
})
})
}
function beforeUpload(file){
if (file.size > 200 * 1024 * 1024) {
message.error('单个文件限制200MB以内');
return false;
}
if(files){
const sameNameFIles = files.filter(item=>item.name === file.name);
if(sameNameFIles.length >= 1){
message.error("请不要重复上传同名文件!");
return false;
}
}
return true;
}
async function onChange({file, fileList: fileListByUpload}){
if(file && (file.status === "done" || file.status === 'uploading' || file.status === 'removed')){
setLoadingBut(true);
const fileList = [...files];
const index = fileList.findIndex(item=>item.uid === file.uid);
if(index !== -1){
fileList[index] = file;
}else{
fileList.push(file);
}
setFiles(fileList);
if(!file.response) return
if(file.response.code !== 200){
message.error(file.response.msg || '上传失败,请联系管理员!')
fileList.pop()
setFiles([...fileList]);
setLoadingBut(false);
}else{
//
await getTypeByFileId(id, file.response.fileId).then((res)=>{
const {data:{code, data: data1, msg}} = res;
if(code !== 200){
return message.error(msg);
}
fileList[fileList.length-1].zoneResourceType = {
id: data1.id,
name: data1.name
}
})
setFiles([...fileList]);
setLoadingBut(false);
}
}
}
function deleteFile(uid){
const fileList = files.filter(item=>item.uid !== uid);
setFiles(fileList);
}
return(
<div className='boxmain pt30 newsCreateBox pb100 sourceCreateBox'>
<Breadcrumb separator=">">
<Breadcrumb.Item><Link className="primaryColor" to={`/zone/${deptId}/source`}>资源列表</Link></Breadcrumb.Item>
<Breadcrumb.Item>{isEdit ? '编辑' : '新建'}资源</Breadcrumb.Item>
</Breadcrumb>
<div className='formBox'>
<Form {...layout} onSubmit={submit}>
<Form.Item label="资源名称">
{getFieldDecorator("name", {
rules:[{ required:true,message:"请输入资源名称!" },
{type: 'string', max: 200, message: "最大长度200"}]
})(
<Input placeholder="请输入资源名称" maxLength={ 200 } width="220px"/>
)}
</Form.Item>
<Form.Item label="资源领域">
{getFieldDecorator("domainId", {
rules:[{ required:true,message:"请选择资源领域!" }]
})(
<Select placeholder="请选择资源领域">
{zoneList && zoneList.map(item =>{
return <Select.Option key={item.id} value={item.id}>{item.name}</Select.Option>
})}
</Select>
)}
</Form.Item>
<Form.Item label="资源简介">
{getFieldDecorator("summary", {
rules:[{ required:true,message:"请输入资源简介!" },
{type: 'string', max: 300, message: "最大长度300"}]
})(
<Input.TextArea placeholder="请输入资源简介" maxLength={ 200 } width="220px"/>
)}
</Form.Item>
<Form.Item label="资源附件" extra={ <span >可上传多个资源文件单个文件限制200MB以内</span> }>
{getFieldDecorator("fileList", {
rules:[{ required:true,message:"请上传资源附件!" }]
})(
<Upload action={getZoneUrl(`/api/file/common/upload?type=resource`)} showUploadList={false} beforeUpload={beforeUpload} onChange={onChange} withCredentials={true}>
<Button>
<Icon type="upload" />单击上传
</Button>
</Upload>
)}
</Form.Item>
{/* 附件展示 */}
<div className="sourceFilesBox">
{files && files.map((item, index)=>{
const {uid, status, response, name, zoneResourceType} = item;
return <div key={index} className="sourseFileItem mb15">
{status === "uploading" ? <Icon type="loading" className='mr10'/> : <Icon type="file" className='mr10'/>}
<span className="fileName task-hide">{name}</span>
<span className='mr20 ml20' style={{width: '100px'}}>{response && response.fileSize}</span>
<span className='mr50'>{zoneResourceType && zoneResourceType.name}</span>
<Icon type="delete" onClick={()=>{deleteFile(uid)}}/>
</div>
})}
</div>
<Form.Item wrapperCol={{ offset: 2 }}>
<Button className='mr20 themeBut' onClick={()=>{history.go(-1)}}>取消</Button>
<Button type="primary" htmlType="submit" loading={loadingBut} className='themeBut'>提交</Button>
</Form.Item>
</Form>
</div>
</div>
)
}
export default Form.create()(SourceCreate);

View File

@ -9,11 +9,13 @@ import { Base64 } from 'js-base64';
import { httpUrl } from '../fetch';
import { AlignCenter, FlexAJ } from '../../Component/layout';
import SourceIcon from '../img/sourceIcon.png';
import { addMeta, setSeoMeta } from 'educoder';
function SourceDetail(props){
const { deptId , sourceid } = props.match.params;
const [ detail , setDetail ] = useState(undefined);
const zonedetail = props.data;
useEffect(()=>{
if(sourceid){
@ -21,6 +23,21 @@ function SourceDetail(props){
}
},[sourceid])
useEffect(()=>{
//
if(detail){
const { name, domainName, summary} = detail;
document.title = `${ name }/${ domainName }`;
addMeta('Keywords', `${ name },${ domainName },${ summary }`);
}
return componentWillUnmount
}, [detail])
function componentWillUnmount() {
document.title= zonedetail.name;
setSeoMeta(`${zonedetail.name},`, zonedetail.name, zonedetail.subTitle, `/zone/${deptId}`)
}
function getDetails(){
getSourceDetail(sourceid).then(response=>{
if(response){

View File

@ -17,6 +17,13 @@ export function getCheckZoneRole(id) {
});
}
export function getCurrentRole(id) {
return fetch({
url: `/zone/zoneFront/${id}/checkCurrentRole`,
method: 'get',
});
}
/********首页接口******/
export function getHomePageList(id) {
return fetch({
@ -115,6 +122,13 @@ export function applyJoin(id,data) {
}
// 资源模块
export function addResource(data) {
return fetch({
url: `/zone/zoneFront/addResource`,
method: 'post',
data: data
});
}
export function getSourceTypeList(id){
return fetch({
url:`/zone/open/${id}/resourceType/list`,
@ -158,7 +172,82 @@ export function delSourceMyList(id){
export function postCreateZone(data) {
return fetch({
url: `/zone/application`,
})
}
// 根据文件id获取专区下资源类别
export function getTypeByFileId(zoneId, fileId){
return fetch({
url:`/zone/resourceType/zone/${zoneId}/getResourceTypeByFileId/${fileId}`,
method: 'get'
})
}
// 新增领域
export function addSourceType(data) {
return fetch({
url: `/zone/resourceType`,
method: 'post',
data: data
});
}
// 修改当前文件对应的资源类别
export function updateResourceTypeByFileId(data) {
return fetch({
url: '/zone/resourceType/updateResourceTypeByFileId',
method: 'PUT',
data: data
});
}
// 获取文章领域列表
export function getDirListById(id){
return fetch({
url:`/cms/doc/open/zone/${id}/dirList`,
method: 'get'
})
}
// 新增文章
export function addNewsByDirId(dirId, data) {
return fetch({
url: `/cms/doc/dir/${dirId}`,
method: 'post',
data: data
});
}
// 获取文章详细信息(需要用户权限)
export function getNewsDetailByAu(id){
return fetch({
url:`/cms/doc/${id}`,
method: 'get',
})
}
// 修改文章详细信息(需要用户权限)
export function updateDoc(id, data) {
return fetch({
url: `/cms/doc/${id}`,
method: 'PUT',
data: data
});
}
// 获取资源详细信息(需要用户权限)
export function getSourceDetailByAu(id){
return fetch({
url:`/zone/zoneFront/myResource/${id}`,
method: 'get',
})
}
// 修改资源详细信息(需要用户权限)
export function updateMyResource(data) {
return fetch({
url: `/zone/zoneFront/editResource`,
method: 'PUT',
data: data
});
}

View File

@ -1,5 +1,6 @@
import axios from 'axios';
import { message , notification } from 'antd';
import cookie from 'react-cookies';
function beforeFetch(actionUrl){
if (window.location.href.indexOf('localhost') < 0) {
@ -8,6 +9,7 @@ function beforeFetch(actionUrl){
const service = axios.create({
headers:{Authorization:"0cd46d63363af9205eb7ccecff574309ce069a97"},
// headers:{Authorization: cookie.load("autologin_trustie")},
baseURL: actionUrl,
timeout: 1800000, // 请求超时时间
});

View File

@ -8,7 +8,7 @@ import { CNotificationHOC } from "../../modules/courses/common/CNotificationHOC"
import { TPMIndexHOC } from "../../modules/tpm/TPMIndexHOC";
import Loadable from "react-loadable";
import Loading from "../../Loading";
import { getMainInfos , getCheckZoneRole } from './api';
import { getMainInfos , getCheckZoneRole, getCurrentRole } from './api';
import PublicBanner from "./Component/publicBanner";
import './index.scss';
import { IsPC } from 'educoder';
@ -16,11 +16,17 @@ import "slick-carousel/slick/slick.css";
import "slick-carousel/slick/slick-theme.css";
import { tempEnum } from "./tempInfo";
import { ImageLayerOfCommentHOC } from "../../modules/page/layers/ImageLayerOfCommentHOC";
import { setSeoMeta } from 'educoder';
const SourceDetail = Loadable({
loader: () => import("./Pages/sourceDetail"),
loading: Loading,
});
const SourceCreate = Loadable({
loader: () => import("./Pages/sourceCreate"),
loading: Loading,
});
const VIP = Loadable({
loader: () => import("./Pages/zoneVIP"),
loading: Loading,
@ -64,6 +70,10 @@ const NewsList = Loadable({
loader: () => import("./Pages/newsList"),
loading: Loading,
});
const NewsCreate = Loadable({
loader: () => import("./Pages/newsCreate"),
loading: Loading,
});
const Main = Loadable({
loader: () => import("./Pages/main"),
@ -81,8 +91,10 @@ function Index(props){
const { deptId } = props.match.params;
const [ id , setId ] = useState(undefined);
const [ temp , setTemp ] = useState(tempEnum.zone);
const [ role , setRole ] = useState(undefined);
const { pathname } = props.history.location;
const sourcedetail = pathname.indexOf(`/zone/${deptId}/newdetail/`)>-1 && IsPC();
const {current_user} = props;
useEffect(()=>{
if(deptId && deptId!=="apply"){
@ -115,7 +127,9 @@ function Index(props){
setId(data.id);
if(data.id){
getAdminUrl(data.id);
getRole(data.id)
}
setSeoMeta(`${data.name},`, data.name, data.subTitle, `/zone/${deptId}`)
}
}).catch(console.error())
}
@ -129,6 +143,15 @@ function Index(props){
}
}).catch(error=>{})
}
function getRole(id){
if(current_user && current_user.login){
getCurrentRole(id).then(res=>{
setRole(res.data.data);
}).catch(error=>{})
}
}
return(
<div className="information_main">
{ (!sourcedetail && deptId!=="apply") && (id ? <PublicBanner {...props} data={data} temp={ temp } adminUrl={adminUrl}/> : <div style={{ width: '100%', height: '450px' }}></div>)}
@ -139,10 +162,22 @@ function Index(props){
<SourceSelfList {...props} {...p} id={id} temp={ temp }/>
)}
></Route>
<Route
path="/zone/:deptId/news/add"
render={(p) => (
<NewsCreate {...props} {...p} id={id} temp={ temp } data={data}/>
)}
></Route>
<Route
path="/zone/:deptId/news/:id/edit"
render={(p) => (
<NewsCreate {...props} {...p} id={id} temp={ temp } data={data}/>
)}
></Route>
<Route
path="/zone/:deptId/news/:cateId"
render={(p) => (
<Main {...props} {...p} id={id} temp={ temp }/>
<Main {...props} {...p} id={id} temp={ temp } role={role}/>
)}
></Route>
<Route
@ -157,16 +192,28 @@ function Index(props){
<SourceSelfList {...props} {...p} id={id} temp={ temp }/>
)}
></Route>
<Route
path="/zone/:deptId/source/add"
render={(p) => (
<SourceCreate {...props} {...p} id={id} temp={ temp } data={data}/>
)}
></Route>
<Route
path="/zone/:deptId/source/:sourceid/edit"
render={(p) => (
<SourceCreate {...props} {...p} id={id} temp={ temp }/>
)}
></Route>
<Route
path="/zone/:deptId/source/:sourceid"
render={(p) => (
<SourceDetail {...props} {...p} id={id} temp={ temp }/>
<SourceDetail {...props} {...p} id={id} temp={ temp } data={data}/>
)}
></Route>
<Route
path="/zone/:deptId/source"
render={(p) => (
<Source {...props} {...p} id={id} temp={ temp }/>
<Source {...props} {...p} id={id} temp={ temp } role={role}/>
)}
></Route>
<Route
@ -184,7 +231,7 @@ function Index(props){
<Route
path="/zone/:deptId/news"
render={(p) => (
<Main {...props} {...p} id={id} temp={ temp }/>
<Main {...props} {...p} id={id} temp={ temp } role={role}/>
)}
></Route>
{data && data.helperShow === 1 && <Route

View File

@ -15,6 +15,20 @@
}
}
// 公共样式
.themeBut{
border-color: var(--primary-color);
color: var(--primary-color);
&:hover, &:active, &:focus{
border-color: var(--light-color);
color: var(--light-color);
}
&.ant-btn-primary{
color: white;
background-color: var(--primary-color);
}
}
.information_main{
background-color:#f3f5f8;
min-height: 100vh;
@ -1521,6 +1535,47 @@
}
}
}
// 新增文章/资源
.titleButBox{
width: 1200px;
margin: 0 auto;
position: relative;
.createButs{
position: absolute;
right: 0;
top: 0;
button{
border-color: var(--primary-color);
color: var(--primary-color);
&:hover{
border-color: var(--light-color);
color: var(--light-color);
}
}
}
}
// 新增文章
.newsCreateBox{
.formBox{
background-color: #fff;
border-radius: 4px;
padding: 30px 35px 50px;
}
}
// 新增资源
.sourceCreateBox{
.sourceFilesBox{
margin-left: 93px;
}
.sourseFileItem{
display: flex;
align-items: center;
}
.fileName{
max-width: 400px;
display: inline-block;
}
}
.primaryColor{
color: var(--primary-color)!important;
}
@ -1667,4 +1722,4 @@
margin:0px 20px;
}
}
}
}

View File

@ -70,24 +70,28 @@ const Mysite = Loadable({
loader: () => import("./website/mySiteList"),
loading: Loading,
});
const CreateSite = Loadable({
loader: () => import("./website/createSite"),
loading: Loading,
});
function Index(props){
const { current_user,mygetHelmetapi , checkIfLogin } = props;
const { pathname } = props.location;
const notice_url = mygetHelmetapi && mygetHelmetapi.common && mygetHelmetapi.common.notice;
const {id_card_verify, website_permission} = current_user;
const [ avatarVisible , setAvatarVisible ] = useState(false);
const [active, setActive] = useState(1);
console.log('active', active);
useEffect(()=>{
if(checkIfLogin() === false){
props.history.push('/login');
props.history.push(`/login?go_page=${pathname}`);
}
},[])
useEffect(()=>{
console.log('pathname', pathname, ["/settings/profile"].indexOf(pathname));
const pattern = /^\/settings\/installbot\/\d+$/;
if(["/settings/profile"].indexOf(pathname) !== -1){
setActive(1);
}else if(["/settings/emails", "/settings/phone", "/settings/password", "/settings/cancel"].indexOf(pathname) !== -1){
@ -100,11 +104,11 @@ function Index(props){
setActive(5);
}else if(["/settings/CLA"].indexOf(pathname) !== -1){
setActive(6);
}else if(["/settings/mybot"].indexOf(pathname) !== -1){
}else if(["/settings/mybot", "/settings/mybot/new"].indexOf(pathname) !== -1){
setActive(7);
}else if(["/settings/installbot"].indexOf(pathname) !== -1){
}else if(["/settings/installbot"].indexOf(pathname) !== -1 || pattern.test(pathname)){
setActive(8);
}else if(["/settings/mysite"].indexOf(pathname) !== -1){
}else if(["/settings/mysite", "/settings/mysite/create"].indexOf(pathname) !== -1){
setActive(9);
}
}, [pathname])
@ -154,10 +158,10 @@ function Index(props){
<li className={active === 7 ?"active":""}><Link to={`/settings/mybot`}><i className="iconfont icon-kaifabot mr5 font-18"></i><span className="text-shodow-bold">我的Bot</span></Link></li>
<li className={active === 8 ?"active":""}><Link to={`/settings/installbot`}><i className="iconfont icon-BOTpeizhi mr5 font-17"></i><span className="text-shodow-bold">Bot安装</span></Link></li>
</ul>
{/* <ul className="securityUl">
<ul className="securityUl">
<li>个人建站</li>
<li className={active === 9 ?"active":""}><Link to={`/settings/mysite`}><i className="iconfont icon-liebiaoicon mr5 font-15"></i><span className="text-shodow-bold">我的站点</span></Link></li>
</ul> */}
</ul>
</div>
<LongWidth>
<Gap>
@ -262,6 +266,13 @@ function Index(props){
<Disposition {...props} {...p}/>
)}
></Route>
{/* 创建站点 */}
{id_card_verify && website_permission && <Route
path="/settings/mysite/create"
render={(p) => (
<CreateSite {...props} {...p}/>
)}
></Route>}
{/* 个人建站 */}
<Route
path="/settings/mysite"

View File

@ -111,4 +111,9 @@
border-color: rgba(230, 126, 34, 1);
color: rgba(230, 126, 34, 1);
}
&.error{
background-color: #fcbabe47;
border-color: #f60011;
color: #f60011;
}
}

View File

@ -0,0 +1,184 @@
import React, { useState, useEffect, Fragment } from "react";
import { Button, message, Form, Input, Select } from "antd";
import "./index.scss";
import "../../users/Material/Index.scss";
import axios from "axios";
import { AlignCenter, AlignTop } from "../../Component/layout";
import { Link } from "react-router-dom";
import { getImageUrl } from "../../../common/UrlTool";
const { TextArea } = Input;
function CreateSite(props) {
const { current_user, history, form } = props;
const { getFieldDecorator, validateFieldsAndScroll, setFieldsValue } = form;
const [tag, setTag] = useState(undefined);
const [language, setLanguage] = useState(undefined);
const [themes, setThemes] = useState([]);
const [theme, setTheme] = useState(undefined);
useEffect(() => {
document.title = "创建站点";
}, []);
useEffect(()=>{
axios.get(`/site_pages/themes.json`, {params: {language_frame: language}}).then(res=>{
if(res && res.status === 200){
setThemes(res.data.themes);
setTheme(res.data.themes[0])
}
})
}, [language])
useEffect(()=>{
if(theme && theme.clone_url && theme && theme.clone_url.indexOf("/") > -1){
let arr = theme && theme.clone_url.split("/");
let first = arr[arr.length-1];
if(first.indexOf(".") > -1){
let second = first.split('.')[0];
if(!second)return;
setFieldsValue({
repository_name:second,
name:second
})
}else{
setFieldsValue({
repository_name:first
})
}
}
}, [theme])
function submit(e) {
e.preventDefault();
validateFieldsAndScroll((err, values) => {
if (!err) {
axios.post(`/projects/page_migrate.json`,{
...values,
clone_addr: theme && theme.clone_url,
theme: theme && theme.name,
user_id: current_user.user_id
}).then(res=>{
if(res && res.status === 200){
message.success("新建成功");
history.push(`/settings/mysite`);
}
})
}
});
}
return (
<Fragment>
<div className="mySites_head mb30"><Link to={`/settings/mysite`} className="font-16">我的站点 / </Link><span>新建站点</span></div>
<Form
form={form}
name="register"
className="createSiteForm"
scrollToFirstError
layout="horizontal"
labelCol={{ span: 3 }}
wrapperCol={{ span: 16 }}
onSubmit={submit}
>
<div className="formTitle font-16 mb20 ml20">站点配置</div>
<Form.Item name="站点名称" label="站点名称">
{getFieldDecorator("site_name", {
rules: [{ required: true, message: "请输入站点名称" },
{type: 'string', max: 50, min: 1, message: "长度1-50"}],
})(<Input placeholder="请输入站点名称" />)}
</Form.Item>
<Form.Item
name="站点标识"
label="站点标识"
className="Create-Form-biaoshi"
>
{getFieldDecorator("identifier", {
rules: [{ required: true, message: "请输入站点标识" },
{pattern: /^[a-zA-Z0-9]{2,100}$/, message: '长度2-100只能包含数字和字母'}],
})(
<Input
onChange={(e) => {
setTag(e.target.value);
}}
placeholder="请输入站点标识"
/>
)}
<span style={{wordBreak: 'break-all'}}>
http://{current_user.login}.kingchan.cn/{tag}
</span>
</Form.Item>
<Form.Item name="建站工具" label="建站工具">
{getFieldDecorator("language_frame", {initialValue: 0})(
<Select style={{ width: 100 }} onChange={(value)=>{setLanguage(value)}}>
<Select.Option value={0}>hugo</Select.Option>
<Select.Option value={1}>jekyll</Select.Option>
<Select.Option value={2}>hexo</Select.Option>
</Select>
)}
</Form.Item>
<Form.Item name="主题选择" label="主题选择" wrapperCol={{span: 20}}>
<AlignTop style={{flexWrap: 'wrap'}}>
{themes && themes.map(item=>{
const {image, name, clone_url} = item;
return <div className="mr20 themeBox" onClick={()=>{setTheme(item)}}>
<i className={`iconfont icon-wancheng ${theme && theme.clone_url === clone_url ? 'active' : ''}`}></i>
<img src={getImageUrl(image)} alt="" width="125px" height="85px"/>
<p className="task-hide" style={{maxWidth: '120px'}}>{name}</p>
</div>
})}
</AlignTop>
</Form.Item>
<div className="formTitle font-16 mb20 ml20">项目配置</div>
<div className="font-15 mb20 ml40">我们会为您生成一个项目来管理您的个人主页请配置您的项目信息</div>
<AlignCenter style={{marginLeft: '58px'}}>
<Form.Item name="拥有者" label="拥有者" style={{width: '260px'}} labelCol={{span: 6}}>
<Input
placeholder={current_user.username}
disabled
/>
</Form.Item>
{/* <span className="mb20 font-18">/</span> 0.87 */}
<Form.Item name="项目标识" label="项目标识" style={{flex: '0.83'}} labelCol={{span: 4}}>
{getFieldDecorator("repository_name", {
rules: [{ required: true, message: "请输入项目标识" },
{pattern: /^[a-zA-Z0-9][a-zA-Z0-9_.-]{2,100}[a-zA-Z0-9]$/, message: "长度2-100只能包含数字、字母、下划线、中划线、英文句号必须以数字和字母开头不能以下划线/中划线/英文句号开头和结尾"}],
})(
<Input placeholder="请输入项目标识"/>
)}
</Form.Item>
</AlignCenter>
<Form.Item
name="项目名称"
label="项目名称"
>
{getFieldDecorator("name", {
rules: [{ required: true, message: "请输入项目名称" },
{type: 'string', max: 50, min: 1, message: "长度1-50"}],
})(
<Input placeholder="请输入项目名称"/>
)}
</Form.Item>
<Form.Item name="项目简介" label="项目简介">
{getFieldDecorator("description", {
rules: [{type: 'string', max: 200, message: "长度200"}]
})(
<TextArea rows={4} />
)}
</Form.Item>
<Form.Item style={{marginLeft: '123px'}} className="mt40">
<Button type="primary" htmlType="submit" className="mr20">
创建站点
</Button>
<Button
onClick={() => {
history.push("/settings/mysite");
}}
>
取消
</Button>
</Form.Item>
</Form>
</Fragment>
);
}
export default Form.create()(CreateSite);

View File

@ -1,8 +1,33 @@
.default_head{
.mySites_head{
height: 65px;
line-height: 64px;
border-bottom: 1px solid rgba(224, 230, 245, 1);
color:#151d40;
font-size:17px;
padding-bottom:20px;
}
.createSiteForm{
.themeBox{
text-align: center;
position: relative;
cursor: pointer;
}
.icon-wancheng{
position: absolute;
right: 4px;
top: -7px;
color: #e5e3e0;
&.active{
color: #ffa13a;
}
}
}
.siteBox{
padding: 15px 0;
border-bottom: 1px dashed #e0e6f5;
.siteName{
color: #05101a;
&:active, &:hover{
color: $primary-color;
}
}
}

View File

@ -1,16 +1,88 @@
import React, { useState, useEffect, Fragment } from "react";
import { Button, Icon, message, Modal } from "antd";
import { Button, Pagination, Spin } from "antd";
import './index.scss';
import '../../users/Material/Index.scss';
import '../bot/exploit/index.scss'
import axios from "axios";
import Nodata from "../../Nodata";
import { FlexAJ } from "../../Component/layout";
function MySiteList(props){
const {current_user} = props;
const {current_user, history} = props;
const {id_card_verify, website_permission} = current_user;
const [total, setTotal] = useState(0);
const [pages, setPages] = useState([]);
const [loading, setLoading] = useState(false);
const [page, setPage] = useState(1);
useEffect(()=>{
document.title='我的站点';
window.scrollTo(0,0);
}, [])
return <Fragment>
<div className="default_head">我的站点</div>
</Fragment>
useEffect(()=>{
if(id_card_verify){
setLoading(true);
//
axios.get(`/site_pages.json`, {params: {limit: 15, page: page}}).then(res=>{
if(res && res.status === 200){
const {total_count, pages} = res.data;
setPages(pages);
setTotal(total_count);
}
setLoading(false);
})
}
}, [id_card_verify, page])
return <Spin spinning={loading}>
<FlexAJ className="mySites_head">
<span>我的站点</span>
{id_card_verify && website_permission && <Button type="primary" onClick={()=>{history.push(`/settings/mysite/create`)}}>新建站点</Button>}
</FlexAJ>
{/* 站点权限被管理员关闭 */}
{id_card_verify && !website_permission && <div className="tipsBox font-15 mt20">您的站点权限被锁定请联系平台管理员</div>}
{/* 未通过实名认证 */}
{!id_card_verify && <Fragment>
<div className="tipsBox font-15 mt30">您尚未通过实名认证无法使用此服务如需使用请先进行实名认证</div>
<Button type="primary" className="mt20" onClick={()=>{history.push(`/settings/verification`)}}>前往验证</Button>
</Fragment>}
{/* 通过实名认证 */}
{id_card_verify && <Fragment>
{!loading && total === 0 ? <div className="mt30">
<div style={{marginBottom: '130px'}}>个人建站是一个免费的静态网页托管服务您可以使用 个人建站服务托管个人主页项目站点等静态网页</div>
<Nodata _html="暂无数据"/>
</div> : <div className="mt10">
{pages && pages.map(item=>{
const {owner, repo, url, state, state_description, build_state} = item
return <FlexAJ>
<div className="siteBox">
<i className="iconfont icon-cangkuyuyanicon font-16 mr5 color-grey-6"></i>
{state && build_state ? <a className={`font-16 siteName`} onClick={()=>{window.open(url)}}>{item.site_name}</a> : <span className={`font-16`}>{item.site_name}</span>}
<span className={`statusBot ml20 font-12 ${state ? build_state ? "public" : "private" : "error"}`}>{state ? build_state ? "已部署" : "未部署" : '被关闭'}</span>
<div className="color-grey-6 mt8">
<span className="">主题</span> {item.theme}
<span className="ml5 mr5 color-grey-ccc">|</span>
建站工具{item.language_frame}
</div>
{!state && <div className="color-grey-6 mt5">关闭原因{state_description}</div>}
</div>
<Button className="themeCorBorBut" onClick={()=>{history.push(`/${owner}/${repo}/service/pages`)}}>去仓库</Button>
</FlexAJ>
})}
<div className="mt50" style={{textAlign: 'center'}}>
<Pagination
simple
current = {page}
pageSize={15}
onChange={(page)=>{setPage(page)}}
total = {total}
hideOnSinglePage
></Pagination>
</div>
</div>}
</Fragment>}
</Spin>
}
export default MySiteList;

View File

@ -1,4 +1,4 @@
import React from 'react';
import React, { useEffect } from 'react';
import { Route, Switch } from 'react-router-dom';
import "./index.scss";
import Loadable from 'react-loadable';
@ -18,7 +18,22 @@ const Reposyncer = Loadable({
loader: () => import('./reposyncer'),
loading: Loading,
})
//
const Pages = Loadable({
loader: () => import('./pages'),
loading: Loading,
})
function ServerIndex(props){
const { projectDetail } = props;
const { owner , projectsId } = props.match.params;
useEffect(()=>{
// tab 3397
if(projectDetail && projectDetail.permission === ""){
props.history.push(`/${owner}/${projectsId}`);
}
}, [projectDetail])
return(
<div className="panels">
<Switch {...props}>
@ -32,6 +47,12 @@ function ServerIndex(props){
() => (<Data {...props}/>)
}
></Route>
{/* 个人建站服务 */}
{projectDetail && projectDetail.author.type === "User" && <Route path="/:owner/:projectsId/service/pages"
render={
() => (<Pages {...props}/>)
}
></Route>}
<Route path="/:owner/:projectsId/service"
render={
() => (<List {...props}/>)

View File

@ -7,7 +7,7 @@ function Main(props){
const { owner , projectsId } = props.match.params;
const [ has_trace_user , setHas_trace_user ] = useState(false);
const { current_user , resetUserInfo, projectDetail, showNotification } = props;
const { current_user , resetUserInfo, projectDetail, showNotification, isDeveloper, isManager, isReporter } = props;
useEffect(()=>{
//
@ -64,6 +64,16 @@ function Main(props){
<Link to={`/${owner}/${projectsId}/service/reposyncer`} className="btnhover">查看详情</Link>
</span>
</li> */}
{projectDetail && projectDetail.author.type === "User" && <li>
<span className="servername">
<img src={require('./img/logo.png')} alt=""/>
<a onClick={openDetail}>个人建站服务</a>
</span>
<p className="task-hide-2 serverdesc">支持HugoJekyllHexo静态网站服务</p>
<span className="serverbtn">
<Link to={`/${owner}/${projectsId}/service/pages`} className="btnhover">查看详情</Link>
</span>
</li>}
</ul>
</div>
)

View File

@ -0,0 +1,207 @@
import React, { Fragment, useEffect, useState } from 'react';
import { Spin, message, Button, Form, Input, Select, Descriptions, Alert } from 'antd';
import axios from 'axios';
import SelectBranch from '../../../forge/Branch/Select';
import './index.scss';
function Pages(props) {
const {current_user, history, form, projectDetail, defaultBranch, isManager} = props;
const { owner , projectsId } = props.match.params;
const {id_card_verify} = current_user;
const { getFieldDecorator, validateFieldsAndScroll } = form;
const [reload, setReload] = useState(undefined);
const [loading, setLoading] = useState(false);
const [pageInfo, setPageInfo] = useState(undefined);
const [tag, setTag] = useState(undefined);
const [branch, setBranch ] = useState(null);
const [building, setBuilding] = useState(false);
const [isBuild, setIsBuild] = useState(false);
const [result, setResult] = useState(undefined);
useEffect(()=>{
//
if(projectDetail){
const { author, name} = projectDetail;
document.title = `个人建站-${author.name}/${name}`;
}
}, [projectDetail])
useEffect(()=>{
if(id_card_verify){
setLoading(true);
//
axios.get(`/site_pages/x.json`, {params:{owner, repo: projectsId}}).then(res=>{
if(res && res.status === 200){
const {last_build_info} = res.data.data
setPageInfo(res.data.data);
last_build_info && last_build_info.length && setResult(last_build_info);
}
setLoading(false);
})
}
}, [id_card_verify, reload])
//
function submit(e) {
e.preventDefault();
validateFieldsAndScroll((err, values) => {
if (!err) {
axios.post(`/site_pages.json`,{
...values,
owner,
repo: projectsId
}).then(res=>{
if(res && res.status === 200){
setReload(Math.random());
message.success("创建成功");
}
})
}
});
}
//
function startBuild(){
setBuilding(true);
axios.post(`/site_pages/${pageInfo.id}/build.json`,{
owner,
repo: projectsId,
branch: branch || defaultBranch
}).then(res=>{
if(res && res.data && res.data.status === 0){
setResult(res.data.data);
}else{
message.error((res && res.data && res.data.message) || "部署失败,请稍后重试");
}
setReload(Math.random());
setIsBuild(false);
setBuilding(false);
})
}
return (
<div className='mb100'>
<div className="servertitle">
<span className="systitle">个人建站服务{!pageInfo && !loading && id_card_verify && isManager && ' - 新建站点'}</span>
</div>
{/* 未通过实名认证 */}
{!id_card_verify && <Fragment>
<div className="tipsBox font-15 mt30">您尚未通过实名认证无法使用此服务如需使用请先进行实名认证</div>
<Button type="primary" className="mt20" onClick={()=>{history.push(`/settings/verification`)}}>前往验证</Button>
</Fragment>}
{id_card_verify && isManager && <Spin spinning={loading}>
{/* 未开通 */}
{!pageInfo ? <Form
form={form}
name="register"
className="mt30"
scrollToFirstError
layout="horizontal"
labelCol={{ span: 2 }}
wrapperCol={{ span: 14 }}
onSubmit={submit}
>
<Form.Item name="站点名称" label="站点名称">
{getFieldDecorator("site_name", {
rules: [{ required: true, message: "请输入站点名称" },
{type: 'string', max: 50, min: 1, message: "长度1-50"}],
})(<Input placeholder="请输入站点名称" />)}
</Form.Item>
<Form.Item
name="站点标识"
label="站点标识"
className="Create-Form-biaoshi"
>
{getFieldDecorator("identifier", {
rules: [{ required: true, message: "请输入站点标识" },
{pattern: /^[a-zA-Z0-9]{2,100}$/, message: '长度2-100只能包含数字和字母'}],
})(
<Input
onChange={(e) => {
setTag(e.target.value);
}}
placeholder="请输入站点标识"
/>
)}
<span style={{wordBreak: 'break-all'}}>
http://{current_user.login}.kingchan.cn/{tag}
</span>
</Form.Item>
<Form.Item name="建站工具" label="建站工具">
{getFieldDecorator("language_frame", {initialValue: 0})(
<Select style={{ width: 100 }}>
<Select.Option value={0}>hugo</Select.Option>
<Select.Option value={1}>jekyll</Select.Option>
<Select.Option value={2}>hexo</Select.Option>
</Select>
)}
</Form.Item>
<Form.Item style={{marginLeft: '100px'}} className="mt40">
<Button type="primary" htmlType="submit" className="mr20">
创建站点
</Button>
<Button
onClick={() => {
history.push(`/${owner}/${projectsId}/service`);
}}
>
取消
</Button>
</Form.Item>
</Form> : pageInfo.state ? <div className='mt30'>
{/* 已开通 */}
<Descriptions title="站点信息">
<Descriptions.Item label="站点名称">
<span onClick={()=>{pageInfo.last_build_at && window.open(pageInfo.url)}} className= {pageInfo.last_build_at && 'theme-btn'}>{pageInfo.site_name}</span>
<span className={`pageStateBox ml20 font-12 ${pageInfo.build_state ? "public" : "private"}`}>{pageInfo.build_state === null ? '未部署' : pageInfo.build_state ? "已部署" : "部署失败"}</span>
</Descriptions.Item>
<Descriptions.Item label="网站地址" span={2}><span onClick={()=>{pageInfo.last_build_at && window.open(pageInfo.url)}} className= {pageInfo.last_build_at && 'theme-btn'}>{pageInfo.url}</span></Descriptions.Item>
<Descriptions.Item label="建站工具">{pageInfo.language_frame}</Descriptions.Item>
<Descriptions.Item label="建站时间">{pageInfo.created_at}</Descriptions.Item>
{pageInfo.last_build_at && <Descriptions.Item label="上次部署时间">{pageInfo.last_build_at}</Descriptions.Item>}
</Descriptions>
{!isBuild && <Button type='primary' style={{width: '135px', height: '34px'}} className='mt20' onClick={()=>{setIsBuild(true)}}>去部署</Button>}
{isBuild && <div>
<div className='mt20 ant-descriptions-title'>部署</div>
<div style={{display: 'inline-flex'}}>
<span>部署分支</span>
<SelectBranch
repo_id={projectDetail && projectDetail.repo_id}
projectsId={projectsId}
branch={branch || defaultBranch}
changeBranch={(params)=>{setBranch(params)}}
owner={owner}
history={props.history}
tagflag={false}
branchList={projectDetail && projectDetail.branches && projectDetail.branches.list}
></SelectBranch>
<span className='color-grey-6 ml30'>选择您要部署的分支</span>
</div>
<div className='mt20'>
<Button type='primary' loading={building} onClick={startBuild}>确定</Button>
<Button type='primary' ghost onClick={()=>{setIsBuild(false)}} className='ml30'>取消</Button>
</div>
</div>}
</div> : <div className='mt30'>
{/* 站点权限被关闭 */}
{pageInfo && <Alert type="error" message={`您的个人站点 ${pageInfo.site_name} 已被关闭,关闭原因为:${pageInfo.state_description}`}></Alert>}
</div>}
{result && <div className='mt30'>
<div className='mt20 ant-descriptions-title'>部署结果</div>
<div className='buildResult'>{result.map(item=> <p>{item}</p>)}</div>
</div>}
</Spin>}
{!isManager && <div className='mt30'>
{/* 非管理员权限 */}
{pageInfo && pageInfo.state && <Descriptions title="站点信息">
<Descriptions.Item label="站点名称"><span onClick={()=>{pageInfo.last_build_at && window.open(pageInfo.url)}} className= {pageInfo.last_build_at && 'theme-btn'}>{pageInfo.site_name}</span></Descriptions.Item>
<Descriptions.Item label="网站地址" span={2}><span onClick={()=>{pageInfo.last_build_at && window.open(pageInfo.url)}} className= {pageInfo.last_build_at && 'theme-btn'}>{pageInfo.url}</span></Descriptions.Item>
<Descriptions.Item label="建站工具">{pageInfo.language_frame}</Descriptions.Item>
<Descriptions.Item label="建站时间">{pageInfo.created_at}</Descriptions.Item>
{pageInfo.last_build_at && <Descriptions.Item label="上次部署时间">{pageInfo.last_build_at}</Descriptions.Item>}
</Descriptions>}
</div>}
</div>
)
}
export default Form.create()(Pages);

View File

@ -0,0 +1,27 @@
.buildResult{
padding: 10px 20px;
background-color: rgb(20, 20, 20);
color: white;
}
.theme-btn{
color: $primary-color;
cursor: pointer;
}
.pageStateBox{
border: 1px solid $primary-color;
border-radius: 5px;
color: $primary-color;
padding: 4px 6px 4px;
background-color: rgba(70, 106, 255, 0.09);
line-height: 12px;
&.public{
background-color: rgba(58, 213, 115, 0.08);
border-color: #25c589;
color: #25c589;
}
&.private{
background-color: rgba(230, 126, 34, 0.08);
border-color: rgba(230, 126, 34, 1);
color: rgba(230, 126, 34, 1);
}
}

View File

@ -7,6 +7,7 @@ const TokenKey = 'autologin_trustie';
function UploadImage({ getImage , url, getImageId, maxSize = 2, action = getUploadActionUrl(), getImageUrl }){
const [ imageUrl , setImageUrl ] = useState(undefined);
const [loading, setLoading] = useState(false);
useEffect(()=>{
setImageUrl(url);
},[url])
@ -33,7 +34,9 @@ function UploadImage({ getImage , url, getImageId, maxSize = 2, action = getUplo
}
//
function handleChange(info){
setLoading(true);
if(info && info.file && info.file.status === "done"){
setLoading(false);
getImageId && getImageId(info.file.response.id);
getImageUrl && getImageUrl(info.file.response.url)
getBase64(info.file.originFileObj, imageUrl =>
@ -58,7 +61,7 @@ function UploadImage({ getImage , url, getImageId, maxSize = 2, action = getUplo
<img src={imageUrl} alt="avatar" style={{ width: '100%' }} />
:
<div>
<Icon type={'plus'} />
<Icon type={loading ? 'loading' : 'plus'} />
<div className="ant-upload-text">点击上传</div>
</div>
}

View File

@ -331,19 +331,20 @@ form{
border: 1px solid #DDDDDD !important;
background-color: #fff !important;
}
.ant-btn.ant-btn-background-ghost{
border-color: #D0D0D0;
}
.ant-btn.ant-btn-background-ghost.ant-btn-primary:hover{
background-color:$primary-color!important;
border-color: $primary-color;
color: #fff;
}
.ant-btn.ant-btn-background-ghost.ant-btn-danger:hover{
background-color: #DF0002!important;
border-color: #DF0002;
color: #fff;
}
// ghost模式按钮如有影响单独修改
// .ant-btn.ant-btn-background-ghost{
// border-color: #D0D0D0;
// }
// .ant-btn.ant-btn-background-ghost.ant-btn-primary:hover{
// background-color:$primary-color!important;
// border-color: $primary-color;
// color: #fff;
// }
// .ant-btn.ant-btn-background-ghost.ant-btn-danger:hover{
// background-color: #DF0002!important;
// border-color: #DF0002;
// color: #fff;
// }
.newPopUl{
li{
height: 30px;

View File

@ -35,7 +35,7 @@ function Index(props){
break;
case '/settings/verification':
setType('4');
documentTitle = "身份认证";
documentTitle = "实名认证";
break;
default:
setType('2');
@ -55,7 +55,7 @@ function Index(props){
<Menu.Item key="3" className="font-16" onClick={()=>{props.history.push('/settings/phone')}}>手机号管理</Menu.Item>
<Menu.Item key="0" className="font-16" onClick={()=>{props.history.push('/settings/emails')}}>邮箱管理</Menu.Item>
<Menu.Item key="1" className="font-16" onClick={()=>{props.history.push('/settings/password')}}>密码管理</Menu.Item>
{/* <Menu.Item key="4" className="font-16" onClick={()=>{props.history.push('/settings/verification')}}>身份认证</Menu.Item> */}
<Menu.Item key="4" className="font-16" onClick={()=>{props.history.push('/settings/verification')}}>实名认证</Menu.Item>
<Menu.Item key="2" className="font-16" onClick={()=>{props.history.push('/settings/cancel')}}>账号注销</Menu.Item>
</Menu>}
</div>

View File

@ -9,7 +9,7 @@ import { getImageUrl } from '../../../common/UrlTool';
export default Form.create()(
forwardRef((props)=>{
const { getFieldDecorator, validateFields , setFieldsValue } = props && props.form;
const { resetUserInfo , current_user } = props;
const { current_user } = props;
const [loading, setLoading] = useState(false);
const [data, setData] = useState(undefined);
const [reload, setReload] = useState(undefined);
@ -18,7 +18,7 @@ export default Form.create()(
if(current_user && current_user.login){
setLoading(true);
//
axios.get(`http://ng.learnerhub.net/api/identity_verifications.json`).then(res=>{
axios.get(`/identity_verifications.json`).then(res=>{
setLoading(false);
if(res && res.status === 200){
if(res.data && res.data.status === 0){
@ -38,7 +38,7 @@ export default Form.create()(
validateFields((error, values) => {
if (!error) {
if(data){
axios.put(`http://ng.learnerhub.net/api/identity_verifications/${data.id}.json`, values).then(res => {
axios.put(`/identity_verifications/${data.id}.json`, values).then(res => {
if(res && res.status === 200){
message.success("提交成功");
setReload(Math.random());
@ -46,7 +46,7 @@ export default Form.create()(
}).catch((error) => {});
}else{
//
axios.post(`http://ng.learnerhub.net/api/identity_verifications.json`, values).then(res=>{
axios.post(`/identity_verifications.json`, values).then(res=>{
if(res && res.status === 200){
message.success("提交成功");
setReload(Math.random());
@ -67,15 +67,16 @@ export default Form.create()(
</div>
)}
{data.state === "已拒绝" && <div className="tipsBox mb20 errorTip">
您提交的身份信息未提供原因{data.description || "无,如有需要请联系平台管理员"}
您提交的身份信息未审核通过原因{data.description || "无,如有需要请联系平台管理员"}
</div>}
{data.state === "已通过" && <Alert className="mb20" type='success' message="您提交的身份信息已通过" />}
{data.state === "已通过" && <Alert className="mb20" type='success' message="您提交的身份信息已审核通过" />}
</Fragment>
)}
<Form layout={"inline"} className="verificationForm">
<Form.Item label="真实姓名" labelCol={{ span: 4 }}>
{getFieldDecorator("name", {
rules: [{ required: true, message: "请输入真实姓名" }],
rules: [{ required: true, message: "请输入真实姓名" },
{type: 'string', max: 50, min: 1, message: "长度1-50"}],
})(
<Input
placeholder="请输入与身份证一致的真实姓名"
@ -83,7 +84,7 @@ export default Form.create()(
/>
)}
</Form.Item>
<Form.Item label="身份证号" labelCol={{ span: 4 }}>
<Form.Item label="身份证号" labelCol={{ span: 4 }}>
{getFieldDecorator("number", {
rules: [
{ required: true, message: "请输入大陆身份证号码" },

View File

@ -9,7 +9,8 @@ import 'codemirror/lib/codemirror.css';
import './css/newquestion.css';
const $ = window.$
const mdIcons = ["bold", "italic", "del", "|", "list-ul", "list-ol", "|", "code", "code-block", "link", "|", "inline-latex", "latex", '|', "image", "table", '|', "line-break", "watch", "clear","fullscreen"];
const mdIcons = ["bold", "italic", "del", "|", "list-ul", "list-ol", "|", "code", "code-block", "link", "|", "image", "table", '|', "line-break", "watch", "clear","fullscreen"];
const mdIconsHasLatex = ["bold", "italic", "del", "|", "list-ul", "list-ol", "|", "code", "code-block", "link", "|", "inline-latex", "latex", '|', "image", "table", '|', "line-break", "watch", "clear","fullscreen"];
const NULL_CH = '▁';
@ -74,7 +75,7 @@ function md_elocalStorage(editor, mdu, id) {
return tid
}
export default ({ mdID, onChange, onCMBeforeChange, onCMBlur, error = false, className = '', noStorage = false, imageExpand = true, placeholder = '', width = '100%', height = 400, initValue = '', emoji, watch=true, showNullButton = false, showResizeBar = false, startInit = true , forMember = true , isCanAtme = false , isQuoteIssue = false , changeAtWhoLoginList, owner, projectsId , isFocus = true}) => {
export default ({ mdID, onChange, onCMBeforeChange, onCMBlur, error = false, className = '', noStorage = false, imageExpand = true, placeholder = '', width = '100%', height = 400, initValue = '', emoji, watch=true, showNullButton = false, showResizeBar = false, startInit = true , forMember = true , isCanAtme = false , isQuoteIssue = false , changeAtWhoLoginList, owner, projectsId , isFocus = true, showLatexButton = true}) => {
const editorEl = useRef();
const resizeBarEl = useRef();
@ -353,7 +354,7 @@ export default ({ mdID, onChange, onCMBeforeChange, onCMBlur, error = false, cla
imageFormats: ["jpg", "jpeg", "gif", "png", "bmp", "webp", "JPG", "JPEG", "GIF", "PNG", "BMP", "WEBP"],
imageUploadURL: getUploadActionUrl(),
toolbarIcons: function () {
return showNullButton ? [...mdIcons, 'null-button'] : mdIcons
return showLatexButton ? mdIconsHasLatex : mdIcons
},
toolbarIconsClass: {
"line-break": "fa-minus",