wuyunfeng hace 1 año
commit
cc17e7205d
Se han modificado 57 ficheros con 9960 adiciones y 0 borrados
  1. 13 0
      .editorconfig
  2. 89 0
      .gitignore
  3. 24 0
      Dockerfile
  4. 69 0
      README.md
  5. 104 0
      api/board.js
  6. 9 0
      app.html
  7. 15 0
      assets/animista.css
  8. 539 0
      assets/demo.css
  9. 49 0
      assets/element-ui.scss
  10. 84 0
      assets/iconfont.css
  11. BIN
      assets/iconfont.ttf
  12. BIN
      assets/iconfont.woff
  13. BIN
      assets/iconfont.woff2
  14. 65 0
      assets/index.scss
  15. 3935 0
      assets/main.css
  16. 28 0
      assets/mixin.scss
  17. 226 0
      assets/sidebar.scss
  18. 48 0
      assets/transition.scss
  19. 25 0
      assets/variables.scss
  20. 11 0
      components/NuxtLogo.vue
  21. 52 0
      components/Tutorial.vue
  22. 10 0
      components/mixin.js
  23. 205 0
      components/mixinnew.js
  24. 78 0
      components/nest-component.vue
  25. 135 0
      components/templates/DragTool.vue
  26. 71 0
      components/templates/common/cloumn-container.vue
  27. 23 0
      components/templates/common/index.js
  28. 63 0
      components/templates/common/row-container.vue
  29. 169 0
      components/templates/common/text-display.vue
  30. 133 0
      components/templates/common/text-display2.vue
  31. 58 0
      components/templates/common/tpl-bed-unit.vue
  32. 450 0
      components/templates/common/tpl-beds-grid.vue
  33. 473 0
      components/templates/common/tpl-header.vue
  34. 449 0
      components/templates/common/tpl-one-cloum.vue
  35. 477 0
      components/templates/common/tpl-three-colum.vue
  36. 461 0
      components/templates/common/tpl-two-cloum.vue
  37. 13 0
      components/templates/index.js
  38. 63 0
      nuxt.config.js
  39. 35 0
      package.json
  40. 456 0
      pages/index/index.vue
  41. 5 0
      plugins/element-ui.js
  42. 9 0
      plugins/vue-vant.js
  43. 6 0
      set-envs.sh
  44. 16 0
      settings.js
  45. 7 0
      static/domain.js
  46. BIN
      static/favicon.ico
  47. 161 0
      store/index.js
  48. 21 0
      store/mutation-types.js
  49. 195 0
      utils/Foundation.js
  50. 29 0
      utils/auth.js
  51. 7 0
      utils/domain.js
  52. 10 0
      utils/get-page-title.js
  53. 21 0
      utils/i18n.js
  54. 117 0
      utils/index.js
  55. 99 0
      utils/request.js
  56. 30 0
      utils/storage.js
  57. 20 0
      utils/validate.js

+ 13 - 0
.editorconfig

@@ -0,0 +1,13 @@
+# editorconfig.org
+root = true
+
+[*]
+indent_style = space
+indent_size = 2
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[*.md]
+trim_trailing_whitespace = false

+ 89 - 0
.gitignore

@@ -0,0 +1,89 @@
+# Created by .ignore support plugin (hsz.mobi)
+### Node template
+# Logs
+/logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+
+# nyc test coverage
+.nyc_output
+
+# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# Bower dependency directory (https://bower.io/)
+bower_components
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (https://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directories
+node_modules/
+jspm_packages/
+
+# TypeScript v1 declaration files
+typings/
+
+# Optional npm cache directory
+.npm
+
+# Optional eslint cache
+.eslintcache
+
+# Optional REPL history
+.node_repl_history
+
+# Output of 'npm pack'
+*.tgz
+
+# Yarn Integrity file
+.yarn-integrity
+
+# dotenv environment variables file
+.env
+
+# parcel-bundler cache (https://parceljs.org/)
+.cache
+
+# next.js build output
+.next
+
+# nuxt.js build output
+.nuxt
+
+# Nuxt generate
+dist
+
+# vuepress build output
+.vuepress/dist
+
+# Serverless directories
+.serverless
+
+# IDE / Editor
+.idea
+
+# Service worker
+sw.*
+
+# macOS
+.DS_Store
+
+# Vim swap files
+*.swp

+ 24 - 0
Dockerfile

@@ -0,0 +1,24 @@
+FROM node:16-slim
+MAINTAINER Javashop
+
+ENV deviceUrl=http://172.28.100.100:8006 language=zh  timeZone=Asia/Shanghai
+# 置入环境变量
+
+RUN mkdir -p /app
+COPY . /app
+WORKDIR /app
+
+COPY ./package*.json ./
+#RUN npm install ajv@6.9.1
+#RUN npm install --registry=https://registry.npm.taobao.org
+
+ENV NODE_ENV=production
+COPY . .
+RUN ["chmod", "+x", "/app/set-envs.sh"]
+#RUN sh -c "/app/set-envs.sh"
+#RUN npm run build
+
+ENV HOST 0.0.0.0
+EXPOSE 3000
+
+CMD sh -c "/app/set-envs.sh && npm run build && npm run start"

+ 69 - 0
README.md

@@ -0,0 +1,69 @@
+# ncs_board_ui_nuxt
+
+## Build Setup
+
+```bash
+# install dependencies
+$ npm install
+
+# serve with hot reload at localhost:3000
+$ npm run dev
+
+# build for production and launch server
+$ npm run build
+$ npm run start
+
+# generate static project
+$ npm run generate
+```
+
+For detailed explanation on how things work, check out the [documentation](https://nuxtjs.org).
+
+## Special Directories
+
+You can create the following extra directories, some of which have special behaviors. Only `pages` is required; you can delete them if you don't want to use their functionality.
+
+### `assets`
+
+The assets directory contains your uncompiled assets such as Stylus or Sass files, images, or fonts.
+
+More information about the usage of this directory in [the documentation](https://nuxtjs.org/docs/2.x/directory-structure/assets).
+
+### `components`
+
+The components directory contains your Vue.js components. Components make up the different parts of your page and can be reused and imported into your pages, layouts and even other components.
+
+More information about the usage of this directory in [the documentation](https://nuxtjs.org/docs/2.x/directory-structure/components).
+
+### `layouts`
+
+Layouts are a great help when you want to change the look and feel of your Nuxt app, whether you want to include a sidebar or have distinct layouts for mobile and desktop.
+
+More information about the usage of this directory in [the documentation](https://nuxtjs.org/docs/2.x/directory-structure/layouts).
+
+
+### `pages`
+
+This directory contains your application views and routes. Nuxt will read all the `*.vue` files inside this directory and setup Vue Router automatically.
+
+More information about the usage of this directory in [the documentation](https://nuxtjs.org/docs/2.x/get-started/routing).
+
+### `plugins`
+
+The plugins directory contains JavaScript plugins that you want to run before instantiating the root Vue.js Application. This is the place to add Vue plugins and to inject functions or constants. Every time you need to use `Vue.use()`, you should create a file in `plugins/` and add its path to plugins in `nuxt.config.js`.
+
+More information about the usage of this directory in [the documentation](https://nuxtjs.org/docs/2.x/directory-structure/plugins).
+
+### `static`
+
+This directory contains your static files. Each file inside this directory is mapped to `/`.
+
+Example: `/static/robots.txt` is mapped as `/robots.txt`.
+
+More information about the usage of this directory in [the documentation](https://nuxtjs.org/docs/2.x/directory-structure/static).
+
+### `store`
+
+This directory contains your Vuex store files. Creating a file in this directory automatically activates Vuex.
+
+More information about the usage of this directory in [the documentation](https://nuxtjs.org/docs/2.x/directory-structure/store).

+ 104 - 0
api/board.js

@@ -0,0 +1,104 @@
+import request from '@/utils/request'
+
+/** 获取科室所有标题设置 */
+export function getBoardTitles(partid) {
+  return request({
+    url: `/ncs/boardtitle/partboardtitle/${partid}`,
+    method: 'get',
+    loading: false
+  })
+}
+
+/** 获取科室所有标题设置 */
+export function getAllTitles(partid) {
+  return request({
+    url: `/boardinfo/screentitles/${partid}`,
+    method: 'get',
+    loading: false
+  })
+}
+
+
+export function getBasicNursecfg(partid) {
+  return request({
+    url: `/boardinfo/getbasicnursecfg/${partid}`,
+    method: 'get',
+    loading: false
+  })
+}
+
+
+export function getpartinfosummary(partid) {
+  return request({
+    url: `/boardinfo/getpartinfosummary/${partid}`,
+    method: 'get',
+    loading: false
+  })
+}
+
+export function getCallingList(partid) {
+  return request({
+    url: `/boardinfo/calling/${partid}`,
+    method: 'get',
+    loading: false
+  })
+}
+
+export function getNurseInfoArray(partid) {
+  return request({
+    url: `/boardinfo/nursemanagerbeds/${partid}`,
+    method: 'get',
+    loading: false
+  })
+}
+
+export function getBoardInfo(partid) {
+  return request({
+    url: `/boardinfo/customboardscreen/${partid}`,
+    method: 'get',
+    loading: false
+  })
+}
+
+export function getBedInfo(partid) {
+  return request({
+    url: `/boardinfo/beditems/${partid}`,
+    method: 'get',
+    loading: false
+  })
+}
+
+export function getPartSetting(partid) {
+  return request({
+    url: `/deviceBed/getPartSetting/${partid}`,
+    method: 'get',
+    loading: false
+  })
+}
+/** 获取科室统计信息*/
+export function getPartStatisticSummary(partid) {
+  return request({
+    url: `/boardinfo/getpartstatisticsummary/${partid}`,
+    method: 'get',
+    loading: false
+  })
+}
+
+/** 获取某科室下的所有看板项 */
+export function getPartList(part_id) {
+  return request({
+    url: `/boardinfo/partboarditem/${part_id}`,
+    method: 'get',
+    loading: false
+  })
+}
+
+/** 获取某科室下的所有看板项 */
+export function getDeviceInfo(mac) {
+  return request({
+    url: `/deviceBed/getBedDeviceInfoByEthMac/${mac}`,
+    method: 'get',
+    loading: false
+  })
+}
+

+ 9 - 0
app.html

@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html {{ HTML_ATTRS }}>
+<head>
+  {{ HEAD }}
+</head>
+<body {{ BODY_ATTRS }}>
+{{ APP }}
+</body>
+</html>

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 15 - 0
assets/animista.css


+ 539 - 0
assets/demo.css

@@ -0,0 +1,539 @@
+/* Logo 字体 */
+@font-face {
+  font-family: "iconfont logo";
+  src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
+  src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
+    url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
+    url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
+    url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
+}
+
+.logo {
+  font-family: "iconfont logo";
+  font-size: 160px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+/* tabs */
+.nav-tabs {
+  position: relative;
+}
+
+.nav-tabs .nav-more {
+  position: absolute;
+  right: 0;
+  bottom: 0;
+  height: 42px;
+  line-height: 42px;
+  color: #666;
+}
+
+#tabs {
+  border-bottom: 1px solid #eee;
+}
+
+#tabs li {
+  cursor: pointer;
+  width: 100px;
+  height: 40px;
+  line-height: 40px;
+  text-align: center;
+  font-size: 16px;
+  border-bottom: 2px solid transparent;
+  position: relative;
+  z-index: 1;
+  margin-bottom: -1px;
+  color: #666;
+}
+
+
+#tabs .active {
+  border-bottom-color: #f00;
+  color: #222;
+}
+
+.tab-container .content {
+  display: none;
+}
+
+/* 页面布局 */
+.main {
+  padding: 30px 100px;
+  width: 960px;
+  margin: 0 auto;
+}
+
+.main .logo {
+  color: #333;
+  text-align: left;
+  margin-bottom: 30px;
+  line-height: 1;
+  height: 110px;
+  margin-top: -50px;
+  overflow: hidden;
+  *zoom: 1;
+}
+
+.main .logo a {
+  font-size: 160px;
+  color: #333;
+}
+
+.helps {
+  margin-top: 40px;
+}
+
+.helps pre {
+  padding: 20px;
+  margin: 10px 0;
+  border: solid 1px #e7e1cd;
+  background-color: #fffdef;
+  overflow: auto;
+}
+
+.icon_lists {
+  width: 100% !important;
+  overflow: hidden;
+  *zoom: 1;
+}
+
+.icon_lists li {
+  width: 100px;
+  margin-bottom: 10px;
+  margin-right: 20px;
+  text-align: center;
+  list-style: none !important;
+  cursor: default;
+}
+
+.icon_lists li .code-name {
+  line-height: 1.2;
+}
+
+.icon_lists .icon {
+  display: block;
+  height: 100px;
+  line-height: 100px;
+  font-size: 42px;
+  margin: 10px auto;
+  color: #333;
+  -webkit-transition: font-size 0.25s linear, width 0.25s linear;
+  -moz-transition: font-size 0.25s linear, width 0.25s linear;
+  transition: font-size 0.25s linear, width 0.25s linear;
+}
+
+.icon_lists .icon:hover {
+  font-size: 100px;
+}
+
+.icon_lists .svg-icon {
+  /* 通过设置 font-size 来改变图标大小 */
+  width: 1em;
+  /* 图标和文字相邻时,垂直对齐 */
+  vertical-align: -0.15em;
+  /* 通过设置 color 来改变 SVG 的颜色/fill */
+  fill: currentColor;
+  /* path 和 stroke 溢出 viewBox 部分在 IE 下会显示
+      normalize.css 中也包含这行 */
+  overflow: hidden;
+}
+
+.icon_lists li .name,
+.icon_lists li .code-name {
+  color: #666;
+}
+
+/* markdown 样式 */
+.markdown {
+  color: #666;
+  font-size: 14px;
+  line-height: 1.8;
+}
+
+.highlight {
+  line-height: 1.5;
+}
+
+.markdown img {
+  vertical-align: middle;
+  max-width: 100%;
+}
+
+.markdown h1 {
+  color: #404040;
+  font-weight: 500;
+  line-height: 40px;
+  margin-bottom: 24px;
+}
+
+.markdown h2,
+.markdown h3,
+.markdown h4,
+.markdown h5,
+.markdown h6 {
+  color: #404040;
+  margin: 1.6em 0 0.6em 0;
+  font-weight: 500;
+  clear: both;
+}
+
+.markdown h1 {
+  font-size: 28px;
+}
+
+.markdown h2 {
+  font-size: 22px;
+}
+
+.markdown h3 {
+  font-size: 16px;
+}
+
+.markdown h4 {
+  font-size: 14px;
+}
+
+.markdown h5 {
+  font-size: 12px;
+}
+
+.markdown h6 {
+  font-size: 12px;
+}
+
+.markdown hr {
+  height: 1px;
+  border: 0;
+  background: #e9e9e9;
+  margin: 16px 0;
+  clear: both;
+}
+
+.markdown p {
+  margin: 1em 0;
+}
+
+.markdown>p,
+.markdown>blockquote,
+.markdown>.highlight,
+.markdown>ol,
+.markdown>ul {
+  width: 80%;
+}
+
+.markdown ul>li {
+  list-style: circle;
+}
+
+.markdown>ul li,
+.markdown blockquote ul>li {
+  margin-left: 20px;
+  padding-left: 4px;
+}
+
+.markdown>ul li p,
+.markdown>ol li p {
+  margin: 0.6em 0;
+}
+
+.markdown ol>li {
+  list-style: decimal;
+}
+
+.markdown>ol li,
+.markdown blockquote ol>li {
+  margin-left: 20px;
+  padding-left: 4px;
+}
+
+.markdown code {
+  margin: 0 3px;
+  padding: 0 5px;
+  background: #eee;
+  border-radius: 3px;
+}
+
+.markdown strong,
+.markdown b {
+  font-weight: 600;
+}
+
+.markdown>table {
+  border-collapse: collapse;
+  border-spacing: 0px;
+  empty-cells: show;
+  border: 1px solid #e9e9e9;
+  width: 95%;
+  margin-bottom: 24px;
+}
+
+.markdown>table th {
+  white-space: nowrap;
+  color: #333;
+  font-weight: 600;
+}
+
+.markdown>table th,
+.markdown>table td {
+  border: 1px solid #e9e9e9;
+  padding: 8px 16px;
+  text-align: left;
+}
+
+.markdown>table th {
+  background: #F7F7F7;
+}
+
+.markdown blockquote {
+  font-size: 90%;
+  color: #999;
+  border-left: 4px solid #e9e9e9;
+  padding-left: 0.8em;
+  margin: 1em 0;
+}
+
+.markdown blockquote p {
+  margin: 0;
+}
+
+.markdown .anchor {
+  opacity: 0;
+  transition: opacity 0.3s ease;
+  margin-left: 8px;
+}
+
+.markdown .waiting {
+  color: #ccc;
+}
+
+.markdown h1:hover .anchor,
+.markdown h2:hover .anchor,
+.markdown h3:hover .anchor,
+.markdown h4:hover .anchor,
+.markdown h5:hover .anchor,
+.markdown h6:hover .anchor {
+  opacity: 1;
+  display: inline-block;
+}
+
+.markdown>br,
+.markdown>p>br {
+  clear: both;
+}
+
+
+.hljs {
+  display: block;
+  background: white;
+  padding: 0.5em;
+  color: #333333;
+  overflow-x: auto;
+}
+
+.hljs-comment,
+.hljs-meta {
+  color: #969896;
+}
+
+.hljs-string,
+.hljs-variable,
+.hljs-template-variable,
+.hljs-strong,
+.hljs-emphasis,
+.hljs-quote {
+  color: #df5000;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-type {
+  color: #a71d5d;
+}
+
+.hljs-literal,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-attribute {
+  color: #0086b3;
+}
+
+.hljs-section,
+.hljs-name {
+  color: #63a35c;
+}
+
+.hljs-tag {
+  color: #333333;
+}
+
+.hljs-title,
+.hljs-attr,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-selector-attr,
+.hljs-selector-pseudo {
+  color: #795da3;
+}
+
+.hljs-addition {
+  color: #55a532;
+  background-color: #eaffea;
+}
+
+.hljs-deletion {
+  color: #bd2c00;
+  background-color: #ffecec;
+}
+
+.hljs-link {
+  text-decoration: underline;
+}
+
+/* 代码高亮 */
+/* PrismJS 1.15.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;
+}

+ 49 - 0
assets/element-ui.scss

@@ -0,0 +1,49 @@
+// cover some element-ui styles
+
+.el-breadcrumb__inner,
+.el-breadcrumb__inner a {
+  font-weight: 400 !important;
+}
+
+.el-upload {
+  input[type="file"] {
+    display: none !important;
+  }
+}
+
+.el-upload__input {
+  display: none;
+}
+
+
+// to fixed https://github.com/ElemeFE/element/issues/2461
+.el-dialog {
+  transform: none;
+  left: 0;
+  position: relative;
+  margin: 0 auto;
+}
+
+// refine element ui upload
+.upload-container {
+  .el-upload {
+    width: 100%;
+
+    .el-upload-dragger {
+      width: 100%;
+      height: 200px;
+    }
+  }
+}
+
+// dropdown
+.el-dropdown-menu {
+  a {
+    display: block
+  }
+}
+
+// to fix el-date-picker css style
+.el-range-separator {
+  box-sizing: content-box;
+}

+ 84 - 0
assets/iconfont.css

@@ -0,0 +1,84 @@
+@font-face {
+  font-family: "iconfont"; /* Project id 4021128 */
+  src: url('iconfont.woff2?t=1681870741668') format('woff2'),
+       url('iconfont.woff?t=1681870741668') format('woff'),
+       url('iconfont.ttf?t=1681870741668') format('truetype');
+}
+
+.iconfont {
+  font-family: "iconfont" !important;
+  font-size: 16px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  align-self: center;
+}
+
+.icon-Columns:before {
+  content: "\e651";
+}
+
+.icon-Row:before {
+  content: "\e655";
+}
+
+.icon-Text:before {
+  content: "\e673";
+}
+
+.icon-24gl-grid:before {
+  content: "\ea98";
+}
+
+.icon-line-card:before {
+  content: "\e65d";
+}
+
+.icon-yisheng:before {
+  content: "\e649";
+}
+
+.icon-hushi:before {
+  content: "\e661";
+}
+
+.icon-Bed:before {
+  content: "\e6ee";
+}
+
+.icon-Bed1:before {
+  content: "\e64b";
+}
+
+.icon-Bed2:before {
+  content: "\e64d";
+}
+
+.icon-yisheng1:before {
+  content: "\e7ad";
+}
+
+.icon-yisheng2:before {
+  content: "\e69d";
+}
+
+.icon-nvhushi1:before {
+  content: "\e6b2";
+}
+
+.icon-bed:before {
+  content: "\e845";
+}
+
+.icon-user-nurse:before {
+  content: "\ebc3";
+}
+
+.icon-a-pinpaiyisheng2x:before {
+  content: "\e62c";
+}
+
+.icon-hushi-01:before {
+  content: "\e61c";
+}
+

BIN
assets/iconfont.ttf


BIN
assets/iconfont.woff


BIN
assets/iconfont.woff2


+ 65 - 0
assets/index.scss

@@ -0,0 +1,65 @@
+@import './variables.scss';
+@import './mixin.scss';
+@import './transition.scss';
+@import './element-ui.scss';
+@import './sidebar.scss';
+
+body {
+  height: 100%;
+  -moz-osx-font-smoothing: grayscale;
+  -webkit-font-smoothing: antialiased;
+  text-rendering: optimizeLegibility;
+  font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
+}
+
+label {
+  font-weight: 700;
+}
+
+html {
+  height: 100%;
+  box-sizing: border-box;
+}
+
+#app {
+  height: 100%;
+}
+
+*,
+*:before,
+*:after {
+  box-sizing: inherit;
+}
+
+a:focus,
+a:active {
+  outline: none;
+}
+
+a,
+a:focus,
+a:hover {
+  cursor: pointer;
+  color: inherit;
+  text-decoration: none;
+}
+
+div:focus {
+  outline: none;
+}
+
+.clearfix {
+  &:after {
+    visibility: hidden;
+    display: block;
+    font-size: 0;
+    content: " ";
+    clear: both;
+    height: 0;
+  }
+}
+
+// main-container global css
+.app-container {
+  padding: 20px;
+}

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 3935 - 0
assets/main.css


+ 28 - 0
assets/mixin.scss

@@ -0,0 +1,28 @@
+@mixin clearfix {
+  &:after {
+    content: "";
+    display: table;
+    clear: both;
+  }
+}
+
+@mixin scrollBar {
+  &::-webkit-scrollbar-track-piece {
+    background: #d3dce6;
+  }
+
+  &::-webkit-scrollbar {
+    width: 6px;
+  }
+
+  &::-webkit-scrollbar-thumb {
+    background: #99a9bf;
+    border-radius: 20px;
+  }
+}
+
+@mixin relative {
+  position: relative;
+  width: 100%;
+  height: 100%;
+}

+ 226 - 0
assets/sidebar.scss

@@ -0,0 +1,226 @@
+#app {
+
+  .main-container {
+    min-height: 100%;
+    transition: margin-left .28s;
+    margin-left: $sideBarWidth;
+    position: relative;
+  }
+
+  .sidebar-container {
+    transition: width 0.28s;
+    width: $sideBarWidth !important;
+    background-color: $menuBg;
+    height: 100%;
+    position: fixed;
+    font-size: 0px;
+    top: 0;
+    bottom: 0;
+    left: 0;
+    z-index: 1001;
+    overflow: hidden;
+
+    // reset element-ui css
+    .horizontal-collapse-transition {
+      transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out;
+    }
+
+    .scrollbar-wrapper {
+      overflow-x: hidden !important;
+    }
+
+    .el-scrollbar__bar.is-vertical {
+      right: 0px;
+    }
+
+    .el-scrollbar {
+      height: 100%;
+    }
+
+    &.has-logo {
+      .el-scrollbar {
+        height: calc(100% - 50px);
+      }
+    }
+
+    .is-horizontal {
+      display: none;
+    }
+
+    a {
+      display: inline-block;
+      width: 100%;
+      overflow: hidden;
+    }
+
+    .svg-icon {
+      margin-right: 16px;
+    }
+
+    .sub-el-icon {
+      margin-right: 12px;
+      margin-left: -2px;
+    }
+
+    .el-menu {
+      border: none;
+      height: 100%;
+      width: 100% !important;
+    }
+
+    // menu hover
+    .submenu-title-noDropdown,
+    .el-submenu__title {
+      &:hover {
+        background-color: $menuHover !important;
+      }
+    }
+
+    .is-active>.el-submenu__title {
+      color: $subMenuActiveText !important;
+    }
+
+    & .nest-menu .el-submenu>.el-submenu__title,
+    & .el-submenu .el-menu-item {
+      min-width: $sideBarWidth !important;
+      background-color: $subMenuBg !important;
+
+      &:hover {
+        background-color: $subMenuHover !important;
+      }
+    }
+  }
+
+  .hideSidebar {
+    .sidebar-container {
+      width: 54px !important;
+    }
+
+    .main-container {
+      margin-left: 54px;
+    }
+
+    .submenu-title-noDropdown {
+      padding: 0 !important;
+      position: relative;
+
+      .el-tooltip {
+        padding: 0 !important;
+
+        .svg-icon {
+          margin-left: 20px;
+        }
+
+        .sub-el-icon {
+          margin-left: 19px;
+        }
+      }
+    }
+
+    .el-submenu {
+      overflow: hidden;
+
+      &>.el-submenu__title {
+        padding: 0 !important;
+
+        .svg-icon {
+          margin-left: 20px;
+        }
+
+        .sub-el-icon {
+          margin-left: 19px;
+        }
+
+        .el-submenu__icon-arrow {
+          display: none;
+        }
+      }
+    }
+
+    .el-menu--collapse {
+      .el-submenu {
+        &>.el-submenu__title {
+          &>span {
+            height: 0;
+            width: 0;
+            overflow: hidden;
+            visibility: hidden;
+            display: inline-block;
+          }
+        }
+      }
+    }
+  }
+
+  .el-menu--collapse .el-menu .el-submenu {
+    min-width: $sideBarWidth !important;
+  }
+
+  // mobile responsive
+  .mobile {
+    .main-container {
+      margin-left: 0px;
+    }
+
+    .sidebar-container {
+      transition: transform .28s;
+      width: $sideBarWidth !important;
+    }
+
+    &.hideSidebar {
+      .sidebar-container {
+        pointer-events: none;
+        transition-duration: 0.3s;
+        transform: translate3d(-$sideBarWidth, 0, 0);
+      }
+    }
+  }
+
+  .withoutAnimation {
+
+    .main-container,
+    .sidebar-container {
+      transition: none;
+    }
+  }
+}
+
+// when menu collapsed
+.el-menu--vertical {
+  &>.el-menu {
+    .svg-icon {
+      margin-right: 16px;
+    }
+    .sub-el-icon {
+      margin-right: 12px;
+      margin-left: -2px;
+    }
+  }
+
+  .nest-menu .el-submenu>.el-submenu__title,
+  .el-menu-item {
+    &:hover {
+      // you can use $subMenuHover
+      background-color: $menuHover !important;
+    }
+  }
+
+  // the scroll bar appears when the subMenu is too long
+  >.el-menu--popup {
+    max-height: 100vh;
+    overflow-y: auto;
+
+    &::-webkit-scrollbar-track-piece {
+      background: #d3dce6;
+    }
+
+    &::-webkit-scrollbar {
+      width: 6px;
+    }
+
+    &::-webkit-scrollbar-thumb {
+      background: #99a9bf;
+      border-radius: 20px;
+    }
+  }
+}

+ 48 - 0
assets/transition.scss

@@ -0,0 +1,48 @@
+// global transition css
+
+/* fade */
+.fade-enter-active,
+.fade-leave-active {
+  transition: opacity 0.28s;
+}
+
+.fade-enter,
+.fade-leave-active {
+  opacity: 0;
+}
+
+/* fade-transform */
+.fade-transform-leave-active,
+.fade-transform-enter-active {
+  transition: all .5s;
+}
+
+.fade-transform-enter {
+  opacity: 0;
+  transform: translateX(-30px);
+}
+
+.fade-transform-leave-to {
+  opacity: 0;
+  transform: translateX(30px);
+}
+
+/* breadcrumb transition */
+.breadcrumb-enter-active,
+.breadcrumb-leave-active {
+  transition: all .5s;
+}
+
+.breadcrumb-enter,
+.breadcrumb-leave-active {
+  opacity: 0;
+  transform: translateX(20px);
+}
+
+.breadcrumb-move {
+  transition: all .5s;
+}
+
+.breadcrumb-leave-active {
+  position: absolute;
+}

+ 25 - 0
assets/variables.scss

@@ -0,0 +1,25 @@
+// sidebar
+$menuText:#bfcbd9;
+$menuActiveText:#409EFF;
+$subMenuActiveText:#f4f4f5; //https://github.com/ElemeFE/element/issues/12951
+
+$menuBg:#304156;
+$menuHover:#263445;
+
+$subMenuBg:#1f2d3d;
+$subMenuHover:#001528;
+
+$sideBarWidth: 210px;
+
+// the :export directive is the magic sauce for webpack
+// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
+:export {
+  menuText: $menuText;
+  menuActiveText: $menuActiveText;
+  subMenuActiveText: $subMenuActiveText;
+  menuBg: $menuBg;
+  menuHover: $menuHover;
+  subMenuBg: $subMenuBg;
+  subMenuHover: $subMenuHover;
+  sideBarWidth: $sideBarWidth;
+}

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 11 - 0
components/NuxtLogo.vue


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 52 - 0
components/Tutorial.vue


+ 10 - 0
components/mixin.js

@@ -0,0 +1,10 @@
+
+export default {
+  props: {
+    /** 数据 */
+    data: {
+      type: Object,
+      default: () => ({})
+    }
+  }
+}

+ 205 - 0
components/mixinnew.js

@@ -0,0 +1,205 @@
+import dragtool from './templates/DragTool'
+import { unix2Date, unix2DateWithTimeZone } from '@/utils/Foundation'
+export default {
+  props: {
+    /** 模块设计数据 */
+    data: {
+      type: Object,
+      default: () => ({})
+    },
+    /** 是否为编辑模式 */
+    isEdit: {
+      type: Boolean,
+      default: false
+    },
+    /** 模块绑定数据  **/
+    bindData: {
+      type: Object,
+      default: () => ({})
+    },
+    /** 床位数据数组索引 */
+    childDataIndex: {
+      type: Number,
+      default: 0
+    },
+    // /** 科室统计信息*/
+    // statisticData: {
+    //   type: Object,
+    //   default: () => ({})
+    // },
+    // /** 自定义看板项目*/
+    // boardCustomerItems: {
+    //   type: Array,
+    //   default: ([])
+    // },
+    /** 动画驱动**/
+    show: {
+      type: Boolean,
+      default: true
+    }
+  },
+  components: {
+    dragtool
+  },
+
+  computed: {
+    moduleComputedStyle() {
+      let backgroundColorNurse = ''
+      let borderColorNurse = ''
+      let boxShadow = ''
+      if (this.data.moduleConfig.styleConfig.borderColorWithNurse && this.data.moduleConfig.styleConfig.borderColorWithNurse !== '') {
+        const nurseId = this.data.moduleConfig.styleConfig.borderColorWithNurse.replace('nurse_color_', '')
+        const nurseOption = this.bindData.items[this.childDataIndex]['list'].filter(p => p.nurse_config === parseInt(nurseId))[0]
+        if (nurseOption) {
+          borderColorNurse = '#' + nurseOption.nurse_color_rbg
+        }
+      }
+      if (this.data.moduleConfig.styleConfig.backgroundColorWithNurse && this.data.moduleConfig.styleConfig.backgroundColorWithNurse !== '') {
+        const nurseId = this.data.moduleConfig.styleConfig.backgroundColorWithNurse.replace('nurse_color_', '')
+        const nurseOption = this.bindData.items[this.childDataIndex]['list'].filter(p => p.nurse_config === parseInt(nurseId))[0]
+        if (nurseOption) {
+          backgroundColorNurse = '#' + nurseOption.nurse_color_rbg
+        }
+      }
+
+      if (this.data.moduleConfig.styleConfig.backgroundColorToday && this.data.moduleConfig.styleConfig.backgroundColorToday !== '') { // 设置日期等于当天的颜色
+        if (this.displayText === unix2DateWithTimeZone(new Date().getTime(), this.data.moduleConfig.dataConfig.textFormat)) {
+          backgroundColorNurse = this.data.moduleConfig.styleConfig.backgroundColorToday
+        }
+      }
+      if (this.data.moduleConfig.styleConfig.boxShadowShow) {
+        boxShadow = '1px 1px 3px 1px #eee'
+        if (this.data.moduleConfig.styleConfig.boxShadowColor && this.data.moduleConfig.styleConfig.boxShadowColor !== '') {
+          boxShadow = '1px 1px 3px 1px ' + this.data.moduleConfig.styleConfig.boxShadowColor
+        }
+      }
+
+      return { ...this.data.moduleConfig.moduleStyle,
+        borderColor: (borderColorNurse === '' ? this.data.moduleConfig.moduleStyle.borderColor : borderColorNurse),
+        backgroundColor: (backgroundColorNurse === '' ? this.data.moduleConfig.moduleStyle.backgroundColor : backgroundColorNurse),
+        boxShadow: boxShadow }
+    },
+    titleComputedStyle() { // 显示单元标题样式计算
+      let titleColor = ''
+      if (this.data.moduleConfig.styleConfig.titleColorWithNurse && this.data.moduleConfig.styleConfig.titleColorWithNurse !== '') {
+        const nurseId = this.data.moduleConfig.styleConfig.titleColorWithNurse.replace('nurse_color_', '')
+        const nurseOption = this.bindData.items[this.childDataIndex]['list'].filter(p => p.nurse_config === parseInt(nurseId))[0]
+        if (nurseOption) {
+          titleColor = '#' + nurseOption.nurse_color_rbg
+        }
+      }
+      return { ...this.data.moduleConfig.titleStyle,
+        color: (titleColor === '' ? this.data.moduleConfig.titleStyle.color : titleColor) }
+    },
+    textComputedStyle() { // 显示单元
+      let textcolor = ''
+      if (this.data.moduleConfig.styleConfig.textColorWithNurse && this.data.moduleConfig.styleConfig.textColorWithNurse !== '') {
+        const nurseId = this.data.moduleConfig.styleConfig.textColorWithNurse.replace('nurse_color_', '')
+        const nurseOption = this.bindData.items[this.childDataIndex]['list'].filter(p => p.nurse_config === parseInt(nurseId))[0]
+        if (nurseOption) {
+          textcolor = '#' + nurseOption.nurse_color_rbg
+        }
+      }
+      if (this.data.moduleConfig.styleConfig.textColorToday && this.data.moduleConfig.styleConfig.textColorToday !== '') { // 设置日期等于当天的颜色
+        if (this.displayText === unix2DateWithTimeZone(new Date().getTime(), this.data.moduleConfig.dataConfig.textFormat)) {
+          textcolor = this.data.moduleConfig.styleConfig.textColorToday
+        }
+      }
+      return {
+        ...this.data.moduleConfig.textStyle,
+        color: (textcolor === '' ? this.data.moduleConfig.textStyle.color : textcolor)
+      }
+    },
+    containerComputedStyle() {
+      if (this.data.moduleConfig.styleConfig.moduleFixed && !this.isEdit) {
+        return {
+          position: 'fixed',
+          width: '100%',
+          bottom: 0,
+          left: 0
+        }
+      }
+    }
+
+  },
+
+  data() {
+    return {
+      systemDate: new Date()
+    }
+  },
+  mounted() {
+    // let _this=this
+
+    this.currentTime()
+  },
+  methods: {
+
+    currentTime() {
+      this.systemDate = new Date()
+      setTimeout(this.currentTime, 1000)
+    },
+
+    /** 获取颜色相关信息 */
+    colors(columnIndex = 0) {
+      const _colors = this.data.columnList[columnIndex].titleColors
+      return {
+        title: `background-color: ${_colors[0]}; background-image: linear-gradient(90deg, ${_colors.join(',')});`,
+        color: (colorIndex = 0) => `color: ${_colors[colorIndex]}`
+      }
+    },
+    // /** 获取区块链接 */
+    // blockHref(block) {
+    //     const { opt_type, opt_value } = block.block_opt
+    //     switch (opt_type) {
+    //         // 链接地址
+    //         case 'URL': return opt_value
+    //         // 商品
+    //         case 'GOODS': return `/goods/${opt_value}`
+    //         // 关键字
+    //         case 'KEYWORD': return `/goods?keyword=${encodeURIComponent(opt_value)}`
+    //         // 店铺
+    //         case 'SHOP': return `/shop/${opt_value}`
+    //         // 分类
+    //         case 'CATEGORY': return `/goods?category=${opt_value}`
+    //         default: return '/'
+    //     }
+    // },
+    /** 构建空的block */
+    emptyBlock(num = 3, type) {
+      return [...new Array(num)].map(() => ({
+        block_type: type,
+        block_value: '',
+        block_opt: {
+          opt_type: 'NONE',
+          opt_value: ''
+        }
+      }))
+    },
+    /** 编辑区块 */
+    handleEditBlock(columnIndex, blockIndex) {
+      // console.log(JSON.stringify(this.data))
+      this.$emit('edit-block', JSON.parse(JSON.stringify(this.data)), columnIndex, blockIndex)
+    },
+    /** 编辑标题 */
+    handleEditTitle(columnIndex) {
+      this.$emit('edit-title', JSON.parse(JSON.stringify(this.data)), columnIndex)
+    },
+    /** 编辑标签 */
+    handleEditTags(columnIndex) {
+      this.$emit('edit-tags', JSON.parse(JSON.stringify(this.data)), columnIndex)
+    },
+
+    deleteModule(unique) {
+      // console.log('model delete', unique)
+      this.$emit('remove', unique)
+    },
+    copyModule(unique) {
+      this.$emit('copy', unique)
+    },
+    activeModule(unique) {
+      this.$emit('active', unique)
+    }
+
+  }
+}

+ 78 - 0
components/nest-component.vue

@@ -0,0 +1,78 @@
+<template>
+    <div >
+    <div v-for="(el,index) in tasks" :key="el.unique"><!--:key="el.unique"-->
+        <template v-if="el.moduleConfig.isCircleChild">
+            <component   :is="templates[el.tpl_id]" :data="el" :bind-data="bindData" :show="show"  :child-data-index="childDataIndex">
+
+                <van-grid-item  v-for="i in ((el.moduleConfig.gridCloumns*el.moduleConfig.gridRows)>(bindData.items?bindData.items.length:0)?(bindData.items?bindData.items.length:0):(el.moduleConfig.gridCloumns*el.moduleConfig.gridRows))" :key="'grid-item'+i" style="padding: 5px;">
+
+                    <nest-component :tasks="el.children" :bind-data="bindData" :show="show"  :child-data-index="i-1" />
+
+                </van-grid-item>
+
+            </component>
+        </template>
+        <template v-else>
+            <component   :is="templates[el.tpl_id]" :data="el" :bind-data="bindData"  :show="show"   :child-data-index="childDataIndex">
+                <!--            <p>{{ el.name }}</p>-->
+                <nest-component :tasks="el.children" :bind-data="bindData" :show="show"   :child-data-index="childDataIndex"/>
+            </component>
+        </template>
+
+    </div>
+    </div>
+</template>
+
+<script>
+    import templates, {templateArray} from './templates'
+    export default {
+        name: "nest-component",
+        props: {
+            tasks: {
+                type:Array,
+                default:([])
+            },
+            bindData:{
+                type:Object,
+                default:()=>({})
+            },
+            childDataIndex:{
+                type:Number,
+                default:0
+            },
+            // statisticData:{
+            //     type:Object,
+            //     default:()=>({})
+            // },
+            // /** 自定义看板项目*/
+            // boardCustomerItems:{
+            //     type:Array,
+            //     default:([])
+            // },
+            /** 动画驱动**/
+            show:{
+                type:Boolean,
+                default:true
+            }
+        },
+        data(){
+            return{
+                templates,
+                templateArray,
+                floorOptions: {
+                    animation: 150,
+                    group: { name: 'tplGroup', put: true },
+                    sort: true,
+                    handle: '.handle-move'
+                },
+            }
+        },
+      mounted() {
+            // console.log('child',this.data.children)
+      }
+    }
+</script>
+
+<style scoped>
+
+</style>

+ 135 - 0
components/templates/DragTool.vue

@@ -0,0 +1,135 @@
+<template>
+
+  <div class="drag-tool" @click.stop="active" :class="{active: state.active === id && isEdit}" :unique="unique" v-if="isEdit">
+    <div class="drag-mask" v-if="mask"></div>
+    <div class="drag-l" v-if="isEdit">
+      <div class="drag-btn _fc-drag-btn active handle-move"  style="cursor: move;">
+        <i class="fc-icon el-icon-rank"></i>
+      </div>
+    </div>
+    <div class="drag-r" v-if="isEdit">
+      <div class="drag-btn" @click="$emit('copy',id)">
+        <i class="fc-icon el-icon-copy-document"></i>
+      </div>
+      <div class="drag-btn" v-if="children" @click="$emit('addChild')">
+        <i class="fc-icon el-icon-circle-plus-outline"></i>
+      </div>
+      <div class="drag-btn drag-btn-danger" @click="$emit('delete',id)">
+        <i class="fc-icon el-icon-delete"></i>
+      </div>
+    </div>
+    <slot name="default" :block="block"></slot>
+  </div>
+  <div v-else >
+    <slot name="default" ></slot>
+  </div>
+</template>
+
+<script>
+let id = 1;
+export default {
+    name: 'DragTool',
+    props: ['dragBtn', 'children', 'unique', 'mask','block','isEdit'],
+
+    data() {
+        return {
+            id: this.unique || id++,
+        };
+    },
+    methods: {
+        active() {
+
+            if (this.state.active === this.id) return;
+
+        }
+    },
+  mounted(){
+
+  },
+    beforeDestroy() {
+        this.state = {};
+    }
+};
+</script>
+
+<style>
+.drag-tool {
+  position: relative;
+  min-height: 20px;
+  box-sizing: border-box;
+  padding: 2px;
+  outline: 1px dashed #2E73FF;
+  overflow: hidden;
+  word-wrap: break-word;
+  word-break: break-all;
+}
+
+.drag-tool .drag-tool {
+  margin: 5px;
+}
+
+.drag-tool + .drag-tool {
+  margin-top: 5px;
+}
+
+.drag-tool.active {
+  outline: 2px solid #2E73FF;
+}
+
+.drag-tool.active > div > .drag-btn {
+  display: flex;
+}
+
+.drag-tool .drag-btn {
+  display: none;
+}
+
+.drag-r {
+  position: absolute;
+  right: 2px;
+  bottom: 2px;
+  z-index: 1904;
+}
+
+.drag-l {
+  position: absolute;
+  top: 0;
+  left: 0;
+  z-index: 1904
+
+}
+
+.drag-btn {
+  height: 18px;
+  width: 18px;
+  color: #fff;
+  background-color: #2E73FF;
+  text-align: center;
+  line-height: 20px;
+  padding-bottom: 1px;
+  float: left;
+  cursor: pointer;
+  justify-content: center;
+}
+
+.drag-btn + .drag-btn {
+  margin-left: 2px;
+}
+
+.drag-btn-danger {
+  background-color: #FF2E2E;
+}
+
+.drag-btn i {
+  font-size: 13px;
+}
+
+.drag-mask{
+    z-index: 1900;
+    position: absolute;
+    top:0;
+    left:0;
+    right:0;
+    bottom: 0;
+;}
+</style>

+ 71 - 0
components/templates/common/cloumn-container.vue

@@ -0,0 +1,71 @@
+
+
+<template>
+
+
+<keep-alive>
+            <el-col :span="Number(data.moduleConfig.spans)" :offset="Number(data.moduleConfig.offset)" :push="Number(data.moduleConfig.push)" :pull="Number(data.moduleConfig.pull)" :style="moduleComputedStyle">
+<!--                <drag-tool :unique="data.unique" @delete="deleteModule" :is-edit="isEdit" @copy="copyModule" @active="activeModule">-->
+                <slot></slot>
+<!--                </drag-tool>-->
+            </el-col>
+
+</keep-alive>
+
+</template>
+
+<script>
+
+    import mixin from '../../mixinnew'
+    import DragTool from "../DragTool";
+    export default {
+        name: "cloumn-container",
+        components: {DragTool},
+        mixins: [mixin],
+        title: '列布局',
+        data(){
+            return{
+            }
+        },
+        dataTpl: {
+            tpl_id: 10,
+            tpl_type: 'BOARD_ITEM',
+            unique:'',
+            isEdit:true,
+            moduleIconClass:'icon-Columns',
+            moduleConfig:{
+                moduleStyle: {
+                    moduleStyle: {
+                        borderColor: '',
+                        // borderWidth:'0px',
+                        borderTopWidth:'0px',
+                        borderRightWidth:'0px',
+                        borderBottomWidth:'0px',
+                        borderLeftWidth:'0px',
+                        borderRadius:'0px',
+                        borderStyle:'solid',
+                        // backgroundColor:''
+                    },
+                },
+                styleConfig:{
+                    // borderColorWithNurse:'', //边框颜色跟随的护理信息分类
+                    // backgroundColorWithNurse:'', //模块背景色跟随的护理信息分类
+                  boxShadowShow:false,
+                  boxShadowColor:''
+                },
+                dataConfig:{
+
+                },
+                spans:8,
+                offset:0,
+                push:0,
+                pull:0,
+            },
+            children:[]
+        }
+    }
+</script>
+
+<style scoped>
+
+</style>

+ 23 - 0
components/templates/common/index.js

@@ -0,0 +1,23 @@
+import tpl_one_cloum from './tpl-one-cloum'
+import tpl_two_cloum from './tpl-two-cloum'
+import tpl_three_cloum from './tpl-three-colum'
+import tpl_header from './tpl-header'
+import tpl_beds_grid from './tpl-beds-grid'
+import tpl_bed_unit from './tpl-bed-unit'
+import text_display from './text-display'
+import text_display2 from './text-display2'
+import row_container from './row-container'
+import column_container from './cloumn-container'
+
+export default {
+    // 1: tpl_one_cloum,
+    // 2: tpl_two_cloum,
+    // 3: tpl_three_cloum,
+    // 4:tpl_header,
+    5:tpl_beds_grid,
+    6:tpl_bed_unit,
+    9:row_container,
+    10:column_container,
+    7:text_display,
+    8:text_display2
+}

+ 63 - 0
components/templates/common/row-container.vue

@@ -0,0 +1,63 @@
+<template>
+<keep-alive>
+    <div style="box-sizing: content-box;" :style="containerComputedStyle">
+<!--        <drag-tool :unique="data.unique" @delete="deleteModule" :is-edit="isEdit" @copy="copyModule" @active="activeModule">-->
+        <el-row :style="moduleComputedStyle">
+            <slot></slot>
+        </el-row>
+<!--        </drag-tool>-->
+    </div>
+</keep-alive>
+</template>
+
+<script>
+
+    import mixin from '../../mixinnew'
+    import DragTool from "../DragTool";
+    export default {
+        name: "row-container",
+        components: {DragTool},
+        mixins: [mixin],
+        title: '行布局',
+        data(){
+            return{
+            }
+        },
+        dataTpl: {
+            tpl_id: 9,
+            tpl_type: 'BOARD_ITEM',
+            unique:'',
+            isEdit:true,
+            moduleIconClass:'icon-Row',
+            moduleConfig:{
+                moduleStyle: {
+                    borderColor: '',
+                    borderWidth:'0px',
+                    borderRadius:'0px',
+                    borderStyle:'solid',
+                    backgroundColor:'',
+                    marginLeft:'0px',
+                    marginTop:'0px',
+                    marginRight:'0px',
+                    marginBottom:'0px',
+
+                },
+                styleConfig:{
+                    borderColorWithNurse:'', //边框颜色跟随的护理信息分类
+                    backgroundColorWithNurse:'', //模块背景色跟随的护理信息分类
+                    moduleFixed:false,
+                  boxShadowShow:false,
+                  boxShadowColor:''
+                },
+                dataConfig:{
+
+                }
+            },
+            children:[]
+        }
+    }
+</script>
+
+<style scoped>
+
+</style>

+ 169 - 0
components/templates/common/text-display.vue

@@ -0,0 +1,169 @@
+<template>
+<keep-alive>
+<!--    <drag-tool  :unique="data.unique" @delete="deleteModule" :is-edit="isEdit" @copy="copyModule" @active="activeModule">-->
+  <div :style="moduleComputedStyle" class="flex">
+    <div class="iconfont" :class="data.moduleConfig.dataConfig.iconClass" v-if="data.moduleConfig.showIcon" :style="data.moduleConfig.iconStyle"></div>
+    <div :style="titleComputedStyle" v-if="data.moduleConfig.showTitle" class="titlewrap">
+      <div class="titleStyle"> {{data.moduleConfig.dataConfig.titleText}}</div>
+    </div>
+    <div :style="textComputedStyle" class="content_item">
+      {{displayText}}
+    </div>
+
+  </div>
+<!--    </drag-tool>-->
+</keep-alive>
+    </template>
+
+    <script>
+    import DragTool from "../DragTool";
+    import mixin from '../../mixinnew'
+    import {unix2Date,unix2DateWithTimeZone} from '@/utils/Foundation'
+    export default {
+
+        name: "text-display",
+        mixins:[mixin],
+        components: {DragTool},
+        title:'内容显示单元',
+        unique:'',
+        computed:{
+          displayText(){
+
+
+              if(this.data.moduleConfig.dataConfig&&this.data.moduleConfig.dataConfig.textWith==='system.date'){ //系统信息
+
+                  return unix2DateWithTimeZone(this.systemDate,this.data.moduleConfig.dataConfig.textFormat)
+              } else if(this.data.moduleConfig.dataConfig&&this.data.moduleConfig.dataConfig.textWith==='part.name'){ //科室信息
+                    let text = this.data.moduleConfig.dataConfig.contentText
+                  if(this.bindData){
+                      text = this.bindData['part_name']
+                  }
+                  return text
+              }else if(this.data.moduleConfig.dataConfig&&this.data.moduleConfig.dataConfig.textWith.indexOf('patient.')>-1) { //患者信息
+                  let text = this.data.moduleConfig.dataConfig.contentText
+                  if(this.bindData){
+                      text = this.bindData.items[this.childDataIndex][this.data.moduleConfig.dataConfig.textWith.replace('patient.','')]
+                      if(this.data.moduleConfig.dataConfig.textType==='日期'){ //格式化日期
+                        text = unix2DateWithTimeZone(text*1000,this.data.moduleConfig.dataConfig.textFormat)
+                      }
+                      if(this.data.moduleConfig.dataConfig.textWith==='patient.sex'){ //格式化性别
+                          text=(text===0?'女':text===1?'男':'未知')
+                      }
+                      if(this.data.moduleConfig.dataConfig.textWith==='patient.age'){
+                          text = (text===null?'':text)+this.bindData.items[this.childDataIndex]['age_unit']
+                      }
+                  }
+                  return text
+              }else if(this.data.moduleConfig.dataConfig&&this.data.moduleConfig.dataConfig.textWith.indexOf('nurse_config_')>-1){ //护理参数
+                    let nurseId = this.data.moduleConfig.dataConfig.textWith.replace('nurse_config_','')
+                    let nurseOption = this.bindData.items[this.childDataIndex]['list'].filter(p=>p.nurse_config===parseInt(nurseId))[0]
+                  if(nurseOption){
+                      return nurseOption['nurse_option_name']
+                  }
+              }else if(this.data.moduleConfig.dataConfig&&this.data.moduleConfig.dataConfig.textWith.indexOf('statistic_')>-1){
+                  let statisticKey = this.data.moduleConfig.dataConfig.textWith.replace('statistic_','')
+                  let statisticItem = this.$store.state.statisticData[statisticKey]
+                  if(statisticItem){
+                      return statisticItem
+                  }
+              }else  {
+                  return this.data.moduleConfig.dataConfig.contentText
+              }
+          }
+        },
+        dataTpl:{
+            tpl_id: 7,
+            tpl_type: 'BOARD_ITEM',
+            templateName:'text-display',
+            isEdit:true,
+            moduleIconClass:'icon-Text',
+            moduleConfig:{
+                moduleStyle: {
+                    borderColor: '',
+                    borderWidth:'0px',
+                    borderRadius:'0px',
+                    borderStyle:'solid',
+                    backgroundColor:'',
+                    justifyContent:'left',
+                    margin:'0px',
+                    padding:'0px',
+                    height:'20px'
+                },
+                styleConfig:{
+                    borderColorWithNurse:'', //边框颜色跟随的护理信息分类
+                    backgroundColorWithNurse:'', //模块背景色跟随的护理信息分类
+                    titleColorWithNurse:'',
+                    textColorWithNurse:'',
+                    textColorToday:'',
+                    backgroundColorToday:''
+                },
+                dataConfig:{
+                    titleText:'Title',
+                    contentText:'文字',
+                    textWith:'',
+                    textType:'文本',
+                    textFormat:'',
+                    iconClass:'' //图标样式类
+                },
+
+                titleStyle:{ //标题样式
+                    fontSize:'14px',
+                    color:'',
+                    fontWeight:'normal',
+                    marginLeft:'0px',
+                    marginRight:'0px',
+                    border:'0px',
+                    width:'auto',
+                    borderColor:'',
+                    paddingRight:'10px',
+                    paddingLeft:'10px',
+                    borderStyle: 'solid',
+                    borderRightWidth: '0px'
+                },
+                textStyle:{ //内容样式
+                   fontSize:'14px',
+                    color:'',
+                    fontWeight:'normal',
+                    marginLeft:'0px',
+                    marginRight:'0px',
+                },
+                iconStyle:{
+                    fontSize:'14px',
+                    color:'',
+                    marginLeft:'0px',
+                    marginTop:'0px',
+                    marginRight:'0px',
+                    marginBottom:'0px'
+                },
+                showTitle:true, //显示标题,
+                showIcon:false
+            },
+            children:[]
+        },
+
+    }
+</script>
+
+<style scoped>
+
+  .content_item{
+    align-self: center;
+  }
+  .titlewrap{
+    align-items: center;
+    display: flex;
+    flex-direction: column;
+    overflow: hidden;
+    overflow-wrap: break-word;
+  }
+  .titleStyle{
+    height: 100%;
+    display: inline-flex;
+    align-items: center;
+    flex-direction: row-reverse;
+    width: 100%;
+    overflow-wrap: break-word;
+    word-break: break-all;
+  }
+
+</style>

+ 133 - 0
components/templates/common/text-display2.vue

@@ -0,0 +1,133 @@
+<template>
+
+    <drag-tool  :unique="data.unique" @delete="deleteModule" :is-edit="isEdit" @copy="copyModule" @active="activeModule">
+        <div :style="moduleComputedStyle" class="flex">
+
+            <div :style="titleComputedStyle" v-if="data.moduleConfig.showTitle"   class="titlewrap"> <div class="titleStyle">{{titleText}}</div>
+            </div>
+            <div class="flex-sub"  :style="textComputedStyle"> <div class="contentStyle">{{displayText}}</div>
+            </div>
+        </div>
+    </drag-tool>
+
+    </template>
+
+    <script>
+    import DragTool from "../DragTool";
+    import mixin from '../../mixinnew'
+    export default {
+        name: "text-display2",
+        mixins:[mixin],
+        components: {DragTool},
+        title:'自定义看板项显示',
+        computed:{
+            displayText(){
+                if(this.data.moduleConfig.dataConfig&&this.data.moduleConfig.dataConfig.displayCustomerItem!==null){ //看板项内容
+
+                    let customItem = this.$store.state.boardCustomerItems.filter(p=>p.his_keyval===this.data.moduleConfig.dataConfig.displayCustomerItem)[0]
+                    if(customItem){
+                        return customItem.area_content
+                    }
+                }
+               return ''
+            },
+            titleText(){
+
+                //重写自定看板项标题
+                if(this.data.moduleConfig.dataConfig&&this.data.moduleConfig.dataConfig.titleText!=='') {
+                    return  this.data.moduleConfig.dataConfig.titleText
+                }
+
+                if(this.data.moduleConfig.dataConfig&&this.data.moduleConfig.dataConfig.displayCustomerItem!==null){ //看板项内容
+
+
+                    let customItem = this.$store.state.boardCustomerItems.filter(p=>p.his_keyval===this.data.moduleConfig.dataConfig.displayCustomerItem)[0]
+                    if(customItem){
+                        return customItem.area_label
+                    }
+
+                }
+               return '标题'
+            }
+
+        },
+
+        dataTpl:{
+            tpl_id: 8,
+            tpl_type: 'BOARD_ITEM',
+            templateName:'text-display2',
+            isEdit:true,
+            unique:'',
+            moduleIconClass:'icon-Text',
+            moduleConfig:{
+                moduleStyle: {
+                    borderColor: '',
+                    borderRadius:'0px',
+                    borderStyle:'solid',
+                    backgroundColor:'',
+                    borderTopWidth:'0px',
+                    borderRightWidth:'0px',
+                    borderBottomWidth:'0px',
+                    borderLeftWidth:'0px',
+                    margin:'0px',
+                    padding:'0px',
+                    height:'40px'
+                },
+                styleConfig:{
+
+                },
+                titleStyle:{ //标题样式
+                    fontSize:'14px',
+                    color:'',
+                    fontWeight:'normal',
+                    marginLeft:'0px',
+                    marginRight:'0px',
+                },
+                textStyle:{ //内容样式
+                    fontSize:'14px',
+                    color:'',
+                    fontWeight:'normal',
+                    marginLeft:'0px',
+                    marginRight:'0px',
+                },
+                dataConfig:{
+                   displayCustomerItem:'',
+                    titleText:''
+                },
+                showTitle:true, //显示标题,
+            },
+            children:([])
+        },
+
+    }
+</script>
+
+<style scoped>
+
+    .contentStyle{
+        margin-left: 10px;
+        display: flex;
+        align-items: center;
+        height: 100%;
+        overflow: hidden;
+        overflow-wrap: break-word;
+        word-break: break-all;
+    }
+    .titlewrap{
+        align-items: center;
+        display: flex;
+        flex-direction: column;
+        overflow: hidden;
+        overflow-wrap: break-word;
+    }
+    .titleStyle{
+        height: 100%;
+        display: inline-flex;
+        align-items: center;
+        flex-direction: row-reverse;
+        width: 100%;
+        overflow-wrap: break-word;
+        word-break: break-all;
+    }
+
+</style>

+ 58 - 0
components/templates/common/tpl-bed-unit.vue

@@ -0,0 +1,58 @@
+<template>
+<keep-alive>
+        <div style="box-sizing: content-box;" >
+<!--            <drag-tool @delete="deleteModule" :is-edit="isEdit" @copy="copyModule" @active="activeModule" :unique="data.unique">-->
+           <div class="box-card  radius" style="box-shadow: 1px 1px 3px 1px #eee" :style="moduleComputedStyle" v-if="isEdit?true:(data.moduleConfig.dataConfig.showOnPatientIn?(bindData.items[childDataIndex].member_id!==null):(bindData.items[childDataIndex].member_id===null))">
+             <slot></slot>
+           </div>
+<!--            </drag-tool>-->
+        </div>
+</keep-alive>
+</template>
+
+<script>
+
+    import mixin from '../../mixinnew'
+    import DragTool from "../DragTool";
+    export default {
+        name: "tpl-bed-unit",
+        components: {DragTool},
+        mixins: [mixin],
+        title: '床位单元格',
+        data(){
+            return{
+            }
+        },
+
+        dataTpl: {
+            tpl_id: 6,
+            tpl_type: 'BOARD_ITEM',
+            unique:'',
+            moduleIconClass:'icon-line-card',
+            isEdit:true,
+            moduleConfig:{
+                moduleStyle: {
+                    borderColor: '#ff0000',
+                    borderWidth:'1px',
+                    borderRadius:'5px',
+                    borderStyle:'solid',
+                    backgroundColor:''
+                },
+                styleConfig:{
+                    borderColorWithNurse:'', //边框颜色跟随的护理信息分类
+                    backgroundColorWithNurse:'', //模块背景色跟随的护理信息分类
+                  boxShadowShow:false,
+                  boxShadowColor:''
+                },
+                dataConfig:{
+                    showOnPatientIn:true
+                }
+            },
+            children:([])
+        }
+    }
+</script>
+
+<style scoped>
+
+</style>

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 450 - 0
components/templates/common/tpl-beds-grid.vue


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 473 - 0
components/templates/common/tpl-header.vue


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 449 - 0
components/templates/common/tpl-one-cloum.vue


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 477 - 0
components/templates/common/tpl-three-colum.vue


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 461 - 0
components/templates/common/tpl-two-cloum.vue


+ 13 - 0
components/templates/index.js

@@ -0,0 +1,13 @@
+import common from './common'
+
+const templates = {
+  ...common
+}
+
+const templateArray = []
+Object.keys(common).forEach(key => {
+  if (common[key].dataTpl) templateArray.push(common[key].dataTpl)
+})
+
+export { templateArray }
+export default templates

+ 63 - 0
nuxt.config.js

@@ -0,0 +1,63 @@
+import env from './static/domain';
+export default {
+  env:{
+    ...env
+  },
+  // Global page headers: https://go.nuxtjs.dev/config-head
+  head: {
+    title: '信息看板',
+    htmlAttrs: {
+      lang: 'en'
+    },
+    meta: [
+      { charset: 'utf-8' },
+      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
+      { hid: 'description', name: 'description', content: '' },
+      { name: 'format-detection', content: 'telephone=no' }
+    ],
+    link: [
+      { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
+    ]
+  },
+  loading: {
+    color: 'blue', // 进度条的颜色
+    failedColor: 'red', // 页面加载失败时的颜色( 当 data 或 fetch 方法返回错误时)
+    height: '2px', // 进度条的高度(在进度条元素的 style 属性上体现)
+    throttle: 200, // 在 ms 中, 在显示进度条之前等待指定的时间。 用于防止条形闪烁
+    duration: 5000, // 进度条的最大显示时长, 单位毫秒。 Nuxt.js 假设页面在该时长内加载完毕
+    continuous: false, // 当加载时间超过duration时, 保持动画进度条
+    css: true, // 设置为 false 以删除默认进度条样式( 并添加自己的样式)
+    rtl: false // 从右到左设置进度条的方向
+  },
+  // Global CSS: https://go.nuxtjs.dev/config-css
+  css: [
+    'element-ui/lib/theme-chalk/index.css',
+    'vant/lib/index.css',
+    '~assets/index.scss',
+    '~assets/iconfont.css',
+    '~assets/main.css'
+  ],
+
+  // Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
+  plugins: [
+    { src: '~plugins/element-ui', ssr: true },
+    { src: '~plugins/vue-vant', ssr: true },
+
+  ],
+
+  // Auto import components: https://go.nuxtjs.dev/config-components
+  components: true,
+
+  // Modules for dev and build (recommended): https://go.nuxtjs.dev/config-modules
+  buildModules: [
+  ],
+
+  // Modules: https://go.nuxtjs.dev/config-modules
+  modules: [
+  ],
+
+  // Build Configuration: https://go.nuxtjs.dev/config-build
+  build: {
+    transpile: [/^element-ui/],
+  }
+}

+ 35 - 0
package.json

@@ -0,0 +1,35 @@
+{
+  "name": "ncs_board_ui_nuxt",
+  "version": "1.0.0",
+  "private": true,
+  "config": {
+    "nuxt": {
+      "host": "0.0.0.0",
+      "port": "3000"
+    }
+  },
+  "scripts": {
+    "dev": "nuxt",
+    "build": "nuxt build",
+    "start": "nuxt start",
+    "generate": "nuxt generate"
+  },
+  "dependencies": {
+    "axios": "0.18.0",
+    "core-js": "^3.25.3",
+    "cross-env": "^7.0.3",
+    "element-ui": "^2.15.10",
+    "js-cookie": "^3.0.5",
+    "moment": "^2.29.4",
+    "moment-timezone": "^0.5.43",
+    "nuxt": "^2.15.8",
+    "psl": "^1.9.0",
+    "sass": "1.26.8",
+    "sass-loader": "^10.1.1",
+    "vant": "^2.12.54",
+    "vue": "^2.7.10",
+    "vue-server-renderer": "^2.7.10",
+    "vue-template-compiler": "^2.7.10"
+  },
+  "devDependencies": {}
+}

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 456 - 0
pages/index/index.vue


+ 5 - 0
plugins/element-ui.js

@@ -0,0 +1,5 @@
+import Vue from 'vue'
+import Element from 'element-ui'
+import locale from 'element-ui/lib/locale/lang/en'
+
+Vue.use(Element, { locale })

+ 9 - 0
plugins/vue-vant.js

@@ -0,0 +1,9 @@
+/**
+ * Created by Andste on 2018/7/9.
+ * 注册Vant组件
+ */
+import Vue from 'vue'
+import {Grid,GridItem,Empty} from 'vant'
+
+
+Vue.use(Grid).use(GridItem).use(Empty)

+ 6 - 0
set-envs.sh

@@ -0,0 +1,6 @@
+echo "module.exports = {
+  deviceUrl: '${deviceUrl}',
+  language: '${language}',
+  timeZone: '${timeZone}'
+}
+" > /app/static/domain.js

+ 16 - 0
settings.js

@@ -0,0 +1,16 @@
+module.exports = {
+
+  title: 'Vue Admin Template',
+
+  /**
+   * @type {boolean} true | false
+   * @description Whether fix the header
+   */
+  fixedHeader: false,
+
+  /**
+   * @type {boolean} true | false
+   * @description Whether show the logo in sidebar
+   */
+  sidebarLogo: false
+}

+ 7 - 0
static/domain.js

@@ -0,0 +1,7 @@
+
+module.exports = {
+  deviceUrl: 'http://localhost:8006',
+  language: 'zh',
+  timeZone:'Asia/Shanghai'
+}
+

BIN
static/favicon.ico


+ 161 - 0
store/index.js

@@ -0,0 +1,161 @@
+import * as types from './mutation-types'
+import Storage from '@/utils/storage'
+import Cookie from 'cookie'
+export const state = () => {
+  const mac = Storage.getItem('mac')
+  const partId = Storage.getItem('partId')
+  const hasRegister = Storage.getItem('hasRegister')
+  return {
+    mac,
+    partId,
+    hasRegister: hasRegister,
+    statisticData:{},
+    boardCustomerItems:[]
+  }
+}
+
+/** mutations */
+export const mutations = {
+  /**
+   * 保存mac地址
+   * @param state
+   * @param data
+   */
+  [types.SET_DEVICE_MAC](state, data) {
+    state.mac = data
+    if (process.client) {
+      Storage.setItem('mac', data)
+    }
+  },
+  /**
+   * 移除mac地址
+   * @param state
+   * @param data
+   */
+  [types.REMOVE_DEVICE_MAC](state) {
+    state.mac = ''
+    Storage.removeItem('mac')
+  },
+  /**
+   * 设置科室Id
+   * @param state
+   * @param token
+   */
+  [types.SET_PART_ID](state, partid) {
+    state.partId = partid
+    if (process.client) {
+      Storage.setItem('partId', partid)
+    }
+  },
+  /**
+   * 移除科室Id
+   * @param state
+   */
+  [types.REMOVE_PART_ID](state) {
+    state.partId = ''
+    if (process.client) {
+      Storage.removeItem('partId')
+    }
+  },
+  /**
+   * 设置注册状态
+   * @param state
+   * @param token
+   */
+  [types.SET_REGISTER_STATUS](state, status) {
+    state.hasRegister = status
+    if (process.client) {
+      Storage.setItem('hasRegister', status)
+    }
+  },
+  /**
+   * 移除注册状态
+   * @param state
+   */
+  [types.REMOVE_REGISTER_STATUS](state) {
+    Storage.setItem('hasRegister', status)
+  },
+  /**
+   * 保存科室统计信息
+   * @param state
+   * @param data
+   */
+  [types.SET_STATISTICS](state,data) {
+    state.statisticData = {...data}
+  },
+  /**
+   * 保存科室自定义项目
+   * @param state
+   * @param data
+   */
+  [types.SET_BOARD_ITEMS](state,data) {
+    state.boardCustomerItems = [...data]
+  }
+}
+
+export const actions = {
+
+   nuxtServerInit({ commit, dispatch }, { req, res }) {
+    // const { env: e } = process
+    // const __env__ = {
+    //   API_MODEL: e.API_MODEL,
+    //   API_BASE: e.API_BASE,
+    //   API_BUYER: e.API_BUYER,
+    //   API_SELLER: e.API_SELLER,
+    //   API_ADMIN: e.API_ADMIN,
+    //   DOMAIN_BUYER_PC: e.DOMAIN_BUYER_PC,
+    //   DOMAIN_BUYER_WAP: e.DOMAIN_BUYER_WAP,
+    //   DOMAIN_SELLER: e.DOMAIN_SELLER,
+    //   DOMAIN_ADMIN: e.DOMAIN_ADMIN
+    // }
+    // await commit(types.SET_ENV_VARS, __env__)
+    //  console.log('req',req)
+    if (req.headers.cookie) {
+      const cookies = Cookie.parse(req.headers.cookie) || {}
+
+      const {mac,hasRegister,partId} =cookies
+      commit(types.SET_DEVICE_MAC, mac)
+      commit(types.SET_PART_ID, partId)
+      commit(types.SET_REGISTER_STATUS, hasRegister)
+      // let { user } = cookies
+      // try {
+      //   user = global.JSON.parse(user)
+      // } catch (e) {
+      //   user = ''
+      // }
+      // await commit('user/SET_USER_INFO', user)
+    }
+    // 获取公共数据
+    // await dispatch('getCommonDataAction')
+  },
+
+  saveDeviceMac: ({commit, dispatch}, mac) => {
+    commit(types.SET_DEVICE_MAC, mac)
+  },
+
+  removeDeviceMac: ({commit, dispatch}) => {
+    commit(types.REMOVE_DEVICE_MAC)
+  },
+
+  savePartId: ({commit, dispatch}, partId) => {
+
+    commit(types.SET_PART_ID, partId)
+  },
+  removePartId: ({commit, dispatch}) => {
+    commit(types.REMOVE_PART_ID)
+  },
+  saveRegisterStatus: ({commit, dispatch}, status) => {
+    commit(types.SET_REGISTER_STATUS, status)
+  },
+  removeRegisterStatus: ({commit, dispatch}) => {
+    commit(types.REMOVE_REGISTER_STATUS)
+  },
+
+  savePartStatistics: ({commit, dispatch}, data) => {
+    commit(types.SET_STATISTICS, data)
+  },
+
+  saveCustomBoardItems: ({commit, dispatch}, data) => {
+    commit(types.SET_BOARD_ITEMS, data)
+  }
+}

+ 21 - 0
store/mutation-types.js

@@ -0,0 +1,21 @@
+
+// 保存设备mac地址
+export const SET_DEVICE_MAC = 'SET_DEVICE_MAC'
+//移除设备mac地址
+export const REMOVE_DEVICE_MAC = 'REMOVE_DEVICE_MAC'
+
+//保存看板科室ID
+export const SET_PART_ID = 'SET_PART_ID'
+//移除科室ID
+export const REMOVE_PART_ID = 'REMOVE_PART_ID'
+
+//保存看板注册状态
+export const SET_REGISTER_STATUS = 'SET_REGISTER_STATUS'
+//移除看板注册状态
+export const REMOVE_REGISTER_STATUS = 'REMOVE_REGISTER_STATUS'
+
+//设置看板统计信息
+export const SET_STATISTICS = 'SET_STATISTICS'
+
+//设置看板自定义项
+export const SET_BOARD_ITEMS = 'SET_BOARD_ITEMS'

+ 195 - 0
utils/Foundation.js

@@ -0,0 +1,195 @@
+/**
+ * 一些常用的基础方法
+ * unixToDate    将unix时间戳转换为指定格式
+ * dateToUnix    将时间转unix时间戳
+ * deepClone     对一个对象进行深拷贝
+ * formatPrice   货币格式化
+ * secrecyMobile 手机号隐私保护
+ * randomString  随机生成指定长度的字符串
+ */
+
+/**
+ * 将unix时间戳转换为指定格式
+ * @param unix   时间戳【秒】
+ * @param format 转换格式
+ * @returns {*|string}
+ */
+
+import moment from 'moment-timezone'
+const timeZone = process.env.timeZone
+export function unixToDate(unix, format) {
+  if (!unix) return unix
+  let _format = format || 'yyyy-MM-dd hh:mm:ss'
+  const d = new Date(unix * 1000)
+  const o = {
+    'M+': d.getMonth() + 1,
+    'd+': d.getDate(),
+    'h+': d.getHours(),
+    'm+': d.getMinutes(),
+    's+': d.getSeconds(),
+    'q+': Math.floor((d.getMonth() + 3) / 3),
+    S: d.getMilliseconds()
+  }
+  if (/(y+)/.test(_format)) _format = _format.replace(RegExp.$1, (d.getFullYear() + '').substr(4 - RegExp.$1.length))
+  for (const k in o) if (new RegExp('(' + k + ')').test(_format)) _format = _format.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length)))
+  return _format
+}
+
+/** 格式化时间戳 */
+export function unix2Date(unix, format) {
+  if (!unix) return unix
+  // let time = moment.tz(unix,timeZone).format(format)
+  // console.log('time',time)
+  // return time
+  let _format = format || 'yyyy-MM-dd hh:mm:ss'
+  const d = new Date(unix)
+
+  const o = {
+    'M+': d.getMonth() + 1,
+    'd+': d.getDate(),
+    'h+': d.getHours(),
+    'm+': d.getMinutes(),
+    's+': d.getSeconds(),
+    'q+': Math.floor((d.getMonth() + 3) / 3),
+    S: d.getMilliseconds()
+  }
+  if (/(y+)/.test(_format)) _format = _format.replace(RegExp.$1, (d.getFullYear() + '').substr(4 - RegExp.$1.length))
+  for (const k in o) if (new RegExp('(' + k + ')').test(_format)) _format = _format.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length)))
+  return _format
+}
+
+export function unix2DateWithTimeZone(unix,format) {
+  if (!unix) return unix
+  let time = moment.tz(unix,timeZone).format(format)
+  return time
+}
+
+/**
+ * 将时间转unix时间戳
+ * @param date
+ * @returns {number} 【秒】
+ */
+export function dateToUnix(date) {
+  let newStr = date.replace(/:/g, '-')
+  newStr = newStr.replace(/ /g, '-')
+  const arr = newStr.split('-')
+  const datum = new Date(Date.UTC(
+    arr[0],
+    arr[1] - 1,
+    arr[2],
+    arr[3] - 8 || -8,
+    arr[4] || 0,
+    arr[5] || 0
+  ))
+  return parseInt(datum.getTime() / 1000)
+}
+
+/**
+ * 对一个对象进行深拷贝
+ * @param object
+ * @returns {*}
+ */
+export function deepClone(object) {
+  let str
+  let newobj = object.constructor === Array ? [] : {}
+  if (typeof object !== 'object') {
+    return object
+  } else if (window.JSON) {
+    str = JSON.stringify(object)
+    newobj = JSON.parse(str)
+  } else {
+    for (const i in object) {
+      if (object.hasOwnProperty(i)) {
+        newobj[i] = typeof object[i] === 'object' ? deepClone(object[i]) : object[i]
+      }
+    }
+  }
+  return newobj
+}
+
+/**
+ * 货币格式化
+ * @param price
+ * @returns {string}
+ */
+export function formatPrice(price) {
+  if (typeof price !== 'number') return price
+  return String(Number(price).toFixed(2)).replace(/\B(?=(\d{3})+(?!\d))/g, ',')
+}
+
+/**
+ * 手机号隐私保护
+ * 隐藏中间四位数字
+ * @param mobile
+ * @returns {*}
+ */
+export function secrecyMobile(mobile) {
+  mobile = String(mobile)
+  if (!/\d{11}/.test(mobile)) {
+    return mobile
+  }
+  return mobile.replace(/(\d{3})(\d{4})(\d{4})/, '$1****$3')
+}
+
+/**
+ * 随机生成指定长度的字符串
+ * @param length
+ * @returns {string}
+ */
+export function randomString(length = 32) {
+  const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
+  const maxPos = chars.length
+  let _string = ''
+  for (let i = 0; i < length; i++) {
+    _string += chars.charAt(Math.floor(Math.random() * maxPos))
+  }
+  return _string
+}
+
+/**
+ * 计算传秒数的倒计时【天、时、分、秒】
+ * @param seconds
+ * @returns {{day : *, hours : *, minutes : *, seconds : *}}
+ */
+export function countTimeDown(seconds) {
+  const leftTime = (time) => {
+    if (time < 10) time = '0' + time
+    return time + ''
+  }
+  return {
+    day: leftTime(parseInt(seconds / 60 / 60 / 24, 10)),
+    hours: leftTime(parseInt(seconds / 60 / 60 % 24, 10)),
+    minutes: leftTime(parseInt(seconds / 60 % 60, 10)),
+    seconds: leftTime(parseInt(seconds % 60, 10))
+  }
+}
+
+/**
+ * 计算当前时间到第二天0点的倒计时[秒]
+ * @returns {number}
+ */
+export function theNextDayTime() {
+  const nowDate = new Date()
+  const time = new Date(nowDate.getFullYear(), nowDate.getMonth(), nowDate.getDate() + 1, 0, 0, 0).getTime() - nowDate.getTime()
+  return parseInt(time / 1000)
+}
+
+export function findNodeById(data, id) {
+  let node = null
+  if (data.length > 0) {
+    for (var i = 0; i < data.length; i++) {
+      if (data[i].tpl_id === id) {
+        node = data[i]
+        break
+      }
+      if (data[i].children && data[i].children.length > 0) {
+        const subresult = findNodeById(data[i].children, id)
+        if (subresult !== null) {
+          node = subresult
+          break
+        }
+      }
+    }
+  }
+  return node
+}

+ 29 - 0
utils/auth.js

@@ -0,0 +1,29 @@
+import Cookies from 'js-cookie'
+
+const TokenKey = 'device_mac'
+
+export function getToken() {
+  return Cookies.get(TokenKey)
+}
+
+export function setToken(token) {
+  return Cookies.set(TokenKey, token)
+}
+
+export function removeToken() {
+  return Cookies.remove(TokenKey)
+}
+
+/**  科室 Cookie **/
+
+export function getPartId() {
+  return Cookies.get('partId')
+}
+
+export function setPartId(partid) {
+  return Cookies.set('partId', partid)
+}
+
+export function removePartId() {
+  return Cookies.remove('partId')
+}

+ 7 - 0
utils/domain.js

@@ -0,0 +1,7 @@
+
+module.exports = {
+  deviceUrl: env.deviceUrl || 'http://119.23.151.229:8006',
+  language: env.language || 'zh',
+  timeZone: env.timeZone || 'Asia/Shanghai'
+}
+

+ 10 - 0
utils/get-page-title.js

@@ -0,0 +1,10 @@
+import defaultSettings from '@/settings'
+
+const title = defaultSettings.title || 'Vue Admin Template'
+
+export default function getPageTitle(pageTitle) {
+  if (pageTitle) {
+    return `${pageTitle} - ${title}`
+  }
+  return `${title}`
+}

+ 21 - 0
utils/i18n.js

@@ -0,0 +1,21 @@
+import Vue from 'vue'
+import enLang from 'element-ui/lib/locale/lang/en'// 如果使用中文语言包请默认支持,无需额外引入,请删除该依赖
+import zhLang from 'element-ui/lib/locale/lang/zh-CN'
+import VueI18n from 'vue-i18n'
+import locale from 'element-ui/lib/locale'
+const language = domain.language
+Vue.use(VueI18n)
+// 创建vue-i18n实例i18n
+const i18n = new VueI18n({
+  // 设置默认语言
+  // locale: 'zh', // 语言标识
+  locale: language, //Storage.getItem('DefaultLanguage') == null ? 'zh' : Storage.getItem('DefaultLanguage'),
+  // 添加多语言(每一个语言标示对应一个语言文件)
+  messages: {
+    'zh': Object.assign(require('../../languages/zh-CN'), zhLang),
+    'en': Object.assign(require('../../languages/en'), enLang)
+  }
+})
+locale.i18n((key, value) => i18n.t(key, value))
+// 暴露i18n
+export default i18n

+ 117 - 0
utils/index.js

@@ -0,0 +1,117 @@
+/**
+ * Created by PanJiaChen on 16/11/18.
+ */
+
+/**
+ * Parse the time to string
+ * @param {(Object|string|number)} time
+ * @param {string} cFormat
+ * @returns {string | null}
+ */
+export function parseTime(time, cFormat) {
+  if (arguments.length === 0 || !time) {
+    return null
+  }
+  const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
+  let date
+  if (typeof time === 'object') {
+    date = time
+  } else {
+    if ((typeof time === 'string')) {
+      if ((/^[0-9]+$/.test(time))) {
+        // support "1548221490638"
+        time = parseInt(time)
+      } else {
+        // support safari
+        // https://stackoverflow.com/questions/4310953/invalid-date-in-safari
+        time = time.replace(new RegExp(/-/gm), '/')
+      }
+    }
+
+    if ((typeof time === 'number') && (time.toString().length === 10)) {
+      time = time * 1000
+    }
+    date = new Date(time)
+  }
+  const formatObj = {
+    y: date.getFullYear(),
+    m: date.getMonth() + 1,
+    d: date.getDate(),
+    h: date.getHours(),
+    i: date.getMinutes(),
+    s: date.getSeconds(),
+    a: date.getDay()
+  }
+  const time_str = format.replace(/{([ymdhisa])+}/g, (result, key) => {
+    const value = formatObj[key]
+    // Note: getDay() returns 0 on Sunday
+    if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value ] }
+    return value.toString().padStart(2, '0')
+  })
+  return time_str
+}
+
+/**
+ * @param {number} time
+ * @param {string} option
+ * @returns {string}
+ */
+export function formatTime(time, option) {
+  if (('' + time).length === 10) {
+    time = parseInt(time) * 1000
+  } else {
+    time = +time
+  }
+  const d = new Date(time)
+  const now = Date.now()
+
+  const diff = (now - d) / 1000
+
+  if (diff < 30) {
+    return '刚刚'
+  } else if (diff < 3600) {
+    // less 1 hour
+    return Math.ceil(diff / 60) + '分钟前'
+  } else if (diff < 3600 * 24) {
+    return Math.ceil(diff / 3600) + '小时前'
+  } else if (diff < 3600 * 24 * 2) {
+    return '1天前'
+  }
+  if (option) {
+    return parseTime(time, option)
+  } else {
+    return (
+      d.getMonth() +
+      1 +
+      '月' +
+      d.getDate() +
+      '日' +
+      d.getHours() +
+      '时' +
+      d.getMinutes() +
+      '分'
+    )
+  }
+}
+
+/**
+ * @param {string} url
+ * @returns {Object}
+ */
+export function param2Obj(url) {
+  const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ')
+  if (!search) {
+    return {}
+  }
+  const obj = {}
+  const searchArr = search.split('&')
+  searchArr.forEach(v => {
+    const index = v.indexOf('=')
+    if (index !== -1) {
+      const name = v.substring(0, index)
+      const val = v.substring(index + 1, v.length)
+      obj[name] = val
+    }
+  })
+  return obj
+}

+ 99 - 0
utils/request.js

@@ -0,0 +1,99 @@
+import axios from 'axios'
+import { MessageBox, Message } from 'element-ui'
+// import store from '@/store'
+//import { getToken } from '@/utils/auth'
+// import { deviceUrl } from '@/utils/domain'
+const qs = require('qs')
+// create an axios instance
+// const deviceUrl = "http://119.23.151.229:8006"
+const service = axios.create({
+  baseURL: process.env.deviceUrl, // url = base url + request url
+  // withCredentials: true, // send cookies when cross-domain requests
+  timeout: 5000, // request timeout
+  paramsSerializer: params => qs.stringify(params, { arryFormat: 'repeat' })
+})
+
+// request interceptor
+service.interceptors.request.use(
+  config => {
+    // do something before request is sent
+    config.headers['Content-type'] = 'application/x-www-form-urlencoded;charset=utf-8'
+    // 如果是put/post请求,用qs.stringify序列化参数
+    const is_put_post = config.method === 'put' || config.method === 'post' || config.method === 'delete'
+    const is_json = config.headers['Content-Type'] === 'application/json'
+    if (is_put_post && is_json) {
+      config.data = JSON.stringify(config.data)
+    }
+    if (is_put_post && !is_json) {
+      config.data = qs.stringify(config.data, { arrayFormat: 'repeat' })
+    }
+
+    // if (store.getters.token) {
+    //   // let each request carry token
+    //   // ['X-Token'] is a custom headers key
+    //   // please modify it according to the actual situation
+    //   // config.headers['X-Token'] = getToken()
+    // }
+    return config
+  },
+  error => {
+    // do something with request error
+    // console.log(error) // for debug
+    return Promise.reject(error)
+  }
+)
+
+// response interceptor
+service.interceptors.response.use(
+  /**
+   * If you want to get http information such as headers or status
+   * Please return  response => response
+  */
+
+  /**
+   * Determine the request status by custom code
+   * Here is just an example
+   * You can also judge the status by HTTP Status Code
+   */
+  response => {
+    return response.data
+    // if the custom code is not 20000, it is judged as an error.
+    // if (res.code !== 20000) {
+    //   Message({
+    //     message: res.message || 'Error',
+    //     type: 'error',
+    //     duration: 5 * 1000
+    //   })
+    //
+    //   // 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
+    //   if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
+    //     // to re-login
+    //     MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', {
+    //       confirmButtonText: 'Re-Login',
+    //       cancelButtonText: 'Cancel',
+    //       type: 'warning'
+    //     }).then(() => {
+    //       store.dispatch('user/resetToken').then(() => {
+    //         location.reload()
+    //       })
+    //     })
+    //   }
+    //   return Promise.reject(new Error(res.message || 'Error'))
+    // } else {
+    //   return res
+    // }
+  },
+  error => {
+    const error_response = error.response || {}
+    const error_data = error_response.data || {}
+
+    Message({
+      message: error_data.message,
+      type: 'error',
+      duration: 5 * 1000
+    })
+    // return Promise.reject(error_data)
+  }
+)
+
+export default service

+ 30 - 0
utils/storage.js

@@ -0,0 +1,30 @@
+/**
+ * Created by Andste on 2018/5/3.
+ */
+
+import Cookies from 'js-cookie'
+const psl = require('psl')
+
+export default {
+  setItem: (key, value, options = {}) => {
+    if (process.client) {
+      const p_psl = psl.parse(document.domain)
+      let domain = p_psl.domain
+      if (/\d+\.\d+\.\d+\.\d+/.test(p_psl.input)) domain = p_psl.input
+      options = { domain, ...options }
+    }
+    Cookies.set(key, value, options)
+  },
+  getItem: (key) => {
+    return Cookies.get(key)
+  },
+  removeItem: (key, options = {}) => {
+    if (process.client) {
+      const p_psl = psl.parse(document.domain)
+      let domain = p_psl.domain
+      if (/\d+\.\d+\.\d+\.\d+/.test(p_psl.input)) domain = p_psl.input
+      options = { domain, ...options }
+    }
+    Cookies.remove(key, options)
+  }
+}

+ 20 - 0
utils/validate.js

@@ -0,0 +1,20 @@
+/**
+ * Created by PanJiaChen on 16/11/18.
+ */
+
+/**
+ * @param {string} path
+ * @returns {Boolean}
+ */
+export function isExternal(path) {
+  return /^(https?:|mailto:|tel:)/.test(path)
+}
+
+/**
+ * @param {string} str
+ * @returns {Boolean}
+ */
+export function validUsername(str) {
+  const valid_map = ['admin', 'editor']
+  return valid_map.indexOf(str.trim()) >= 0
+}