Browse Source

Merge branch 'master' of http://192.168.1.220:10080/Amoy2/intelligent-medicine-cabinet

lincl 2 years ago
parent
commit
8487ca0721
99 changed files with 5154 additions and 944 deletions
  1. 1 1
      mini-pro-web/.env.development
  2. 1 2
      mini-pro-web/.env.production
  3. 8 0
      mini-pro-web/.env.test
  4. 22 0
      mini-pro-web/package-lock.json
  5. 2 0
      mini-pro-web/package.json
  6. 3 3
      mini-pro-web/public/index.html
  7. 1 0
      mini-pro-web/public/version.txt
  8. BIN
      mini-pro-web/public/versions/1.0.3.jar
  9. 128 16
      mini-pro-web/src/api/api-medicineAbinet.js
  10. 47 0
      mini-pro-web/src/api/login.js
  11. BIN
      mini-pro-web/src/assets/images/Waiting-medicine.png
  12. BIN
      mini-pro-web/src/assets/images/beihuo.png
  13. BIN
      mini-pro-web/src/assets/images/beihuojilu.png
  14. BIN
      mini-pro-web/src/assets/images/buhuo.png
  15. BIN
      mini-pro-web/src/assets/images/buhuojilu.png
  16. BIN
      mini-pro-web/src/assets/images/chufangdan_img.png
  17. BIN
      mini-pro-web/src/assets/images/chufangdan_img_01.png
  18. BIN
      mini-pro-web/src/assets/images/diandanguanli01_icon.png
  19. BIN
      mini-pro-web/src/assets/images/diandanguanli_icon.png
  20. BIN
      mini-pro-web/src/assets/images/drug.png
  21. BIN
      mini-pro-web/src/assets/images/equipment.png
  22. BIN
      mini-pro-web/src/assets/images/offline-equipment.png
  23. BIN
      mini-pro-web/src/assets/images/offline-medicine.png
  24. BIN
      mini-pro-web/src/assets/images/order.png
  25. BIN
      mini-pro-web/src/assets/images/peitu_img.png
  26. BIN
      mini-pro-web/src/assets/images/quyaochishu_img.png
  27. BIN
      mini-pro-web/src/assets/images/quyaocishu_img.png
  28. BIN
      mini-pro-web/src/assets/images/replenishment.png
  29. BIN
      mini-pro-web/src/assets/images/shebeigaikuang_img.png
  30. BIN
      mini-pro-web/src/assets/images/shebeigaunli01_icon.png
  31. BIN
      mini-pro-web/src/assets/images/shebeigaunli_icon.png
  32. BIN
      mini-pro-web/src/assets/images/temperature.png
  33. BIN
      mini-pro-web/src/assets/images/thermometer.png
  34. BIN
      mini-pro-web/src/assets/images/waiting-equipment.png
  35. BIN
      mini-pro-web/src/assets/images/yaopingaikuang.png
  36. 29 3
      mini-pro-web/src/assets/styles/index.scss
  37. 50 8
      mini-pro-web/src/components/ProductItem/index.vue
  38. 6 2
      mini-pro-web/src/components/layout/NavLayout.vue
  39. 83 24
      mini-pro-web/src/components/layout/components/AppBotNav.vue
  40. 5 1
      mini-pro-web/src/components/layout/components/AppMain.vue
  41. 2 1
      mini-pro-web/src/components/layout/styles/appBotNav.scss
  42. 55 0
      mini-pro-web/src/directive/longpress.js
  43. 3 0
      mini-pro-web/src/main.js
  44. 25 0
      mini-pro-web/src/mixins/common.js
  45. 16 5
      mini-pro-web/src/router/device.js
  46. 96 33
      mini-pro-web/src/router/index.js
  47. 2 2
      mini-pro-web/src/router/order.js
  48. 53 11
      mini-pro-web/src/router/replenishment.js
  49. 1 1
      mini-pro-web/src/store/getters.js
  50. 5 2
      mini-pro-web/src/store/index.js
  51. 16 2
      mini-pro-web/src/store/modules/app.js
  52. 3 1
      mini-pro-web/src/store/modules/user.js
  53. 3 0
      mini-pro-web/src/utils/navigator/README.md
  54. 1 1
      mini-pro-web/src/views/device/cargoLane/index.vue
  55. 51 3
      mini-pro-web/src/views/device/cargoLane/setting.vue
  56. 191 51
      mini-pro-web/src/views/device/detail.vue
  57. 190 65
      mini-pro-web/src/views/device/index.vue
  58. 79 0
      mini-pro-web/src/views/device/infoLog/TimePicker.vue
  59. 93 58
      mini-pro-web/src/views/device/infoLog/deviceLog.vue
  60. 68 71
      mini-pro-web/src/views/device/infoLog/faultInfo.vue
  61. 31 11
      mini-pro-web/src/views/device/infoLog/index.vue
  62. 62 51
      mini-pro-web/src/views/device/infoLog/offlineLog.vue
  63. 3 1
      mini-pro-web/src/views/device/sell.vue
  64. 30 0
      mini-pro-web/src/views/device/stock.vue
  65. 21 18
      mini-pro-web/src/views/device/temperature/index.vue
  66. 20 11
      mini-pro-web/src/views/drug/list.vue
  67. 505 139
      mini-pro-web/src/views/index/Index.vue
  68. 327 0
      mini-pro-web/src/views/index/scss/index.scss
  69. 1 1
      mini-pro-web/src/views/login/FotgetPassword.vue
  70. 6 37
      mini-pro-web/src/views/login/Login.vue
  71. 2 2
      mini-pro-web/src/views/login/Register.vue
  72. 53 0
      mini-pro-web/src/views/machine/components/Dialog.vue
  73. 272 81
      mini-pro-web/src/views/machine/index.vue
  74. 474 0
      mini-pro-web/src/views/order/components/Filter.vue
  75. 1 0
      mini-pro-web/src/views/order/detail/components/DeviceInfo.vue
  76. 2 1
      mini-pro-web/src/views/order/detail/components/DrugList.vue
  77. 2 1
      mini-pro-web/src/views/order/detail/components/LogList.vue
  78. 2 2
      mini-pro-web/src/views/order/detail/index.vue
  79. 125 18
      mini-pro-web/src/views/order/list.vue
  80. 10 9
      mini-pro-web/src/views/personal/index.vue
  81. 2 2
      mini-pro-web/src/views/replenishment/device/detail.vue
  82. 1 1
      mini-pro-web/src/views/replenishment/device/list.vue
  83. 6 6
      mini-pro-web/src/views/replenishment/index.vue
  84. 2 2
      mini-pro-web/src/views/replenishment/picking/detail.vue
  85. 82 26
      mini-pro-web/src/views/replenishment/picking/list.vue
  86. 26 0
      mini-pro-web/src/views/replenishment/picking/outList.vue
  87. 4 4
      mini-pro-web/src/views/replenishment/record/detail.vue
  88. 61 49
      mini-pro-web/src/views/replenishment/record/list.vue
  89. 13 5
      mini-pro-web/src/views/replenishment/start/components/SetStockDialog.vue
  90. 573 38
      mini-pro-web/src/views/replenishment/start/deviceDetail.vue
  91. 1 1
      mini-pro-web/src/views/replenishment/start/deviceList.vue
  92. 44 5
      mini-pro-web/src/views/replenishment/start/productDetail.vue
  93. 604 0
      mini-pro-web/src/views/replenishment/start/quick.vue
  94. 3 3
      mini-pro-web/src/views/replenishment/start/selProduct.vue
  95. 218 0
      mini-pro-web/src/views/replenishment/stockUp/createOut.vue
  96. 164 46
      mini-pro-web/src/views/replenishment/stockUp/detail.vue
  97. 5 5
      mini-pro-web/src/views/replenishment/stockUp/deviceList.vue
  98. 56 0
      mini-pro-web/src/views/replenishment/stockUp/drugList.vue
  99. 1 1
      mini-pro-web/vue.config.js

+ 1 - 1
mini-pro-web/.env.development

@ -11,4 +11,4 @@ VUE_APP_IM_API = 'http://ehr.yihu.com/api/v2'
VUE_APP_PRE_PATH = '/hlwyy/intelligent-medicine-abinet'
VUE_APP_APPID = "wx79a7f451c8c30308"
VUE_APP_WXID = hz_yyyzh_wx
VUE_APP_WXID = znyg_wx

+ 1 - 2
mini-pro-web/.env.production

@ -13,5 +13,4 @@ VUE_APP_MACHINE_SOCKET_URL = 'ws://10.95.22.10:9660/cabinet/websocket/'
#https://zb.xmtyw.cn/medicine
VUE_APP_APPID = "wx2c55f5b7b2f3cb56"
VUE_APP_WXID = hz_yyyzh_wx
VUE_APP_CLIENTID = "ihealth_pa8DIRJasL"
VUE_APP_WXID = znyg_wx

+ 8 - 0
mini-pro-web/.env.test

@ -0,0 +1,8 @@
VUE_APP_BASE_API = 'http://ehr.yihu.com/hlwyy'
VUE_APP_IMAGE_SERVER = 'http://ehr.yihu.com/fastdfs/'
VUE_APP_SOCKET_URL = 'http://ehr.yihu.com'
VUE_APP_IM_API = 'http://ehr.yihu.com/api/v2'
VUE_APP_PRE_PATH = '/hlwyy/intelligent-medicine-abinet'
VUE_APP_APPID = ""
VUE_APP_WXID = ""

+ 22 - 0
mini-pro-web/package-lock.json

@ -4643,6 +4643,15 @@
        "safer-buffer": "^2.1.0"
      }
    },
    "echarts": {
      "version": "5.2.2",
      "resolved": "https://registry.npmjs.org/echarts/-/echarts-5.2.2.tgz",
      "integrity": "sha512-yxuBfeIH5c+0FsoRP60w4De6omXhA06c7eUYBsC1ykB6Ys2yK5fSteIYWvkJ4xJVLQgCvAdO8C4mN6MLeJpBaw==",
      "requires": {
        "tslib": "2.3.0",
        "zrender": "5.2.1"
      }
    },
    "ee-first": {
      "version": "1.1.1",
      "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@ -11406,6 +11415,11 @@
      "integrity": "sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==",
      "dev": true
    },
    "tslib": {
      "version": "2.3.0",
      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
      "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
    },
    "tty-browserify": {
      "version": "0.0.0",
      "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
@ -12818,6 +12832,14 @@
      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.7.tgz",
      "integrity": "sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw==",
      "dev": true
    },
    "zrender": {
      "version": "5.2.1",
      "resolved": "https://registry.npmjs.org/zrender/-/zrender-5.2.1.tgz",
      "integrity": "sha512-M3bPGZuyLTNBC6LiNKXJwSCtglMp8XUEqEBG+2MdICDI3d1s500Y4P0CzldQGsqpRVB7fkvf3BKQQRxsEaTlsw==",
      "requires": {
        "tslib": "2.3.0"
      }
    }
  }
}

+ 2 - 0
mini-pro-web/package.json

@ -5,6 +5,7 @@
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "build:test": "vue-cli-service build --mode test",
    "build:dev": "vue-cli-service build --mode development"
  },
  "dependencies": {
@ -13,6 +14,7 @@
    "core-js": "^3.6.5",
    "crypto-js": "^4.0.0",
    "custom-components-mobile": "git+http://192.168.1.220:10080/lincl/custom-components-mobile.git#master",
    "echarts": "^5.2.2",
    "exif-js": "^2.3.0",
    "js-cookie": "^2.2.1",
    "lodash": "^4.17.20",

+ 3 - 3
mini-pro-web/public/index.html

@ -3,9 +3,9 @@
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0, viewport-fit=cover">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <title>智能药房</title>
    <title>智慧药房</title>
    <script src="<%= BASE_URL %>js/touch-simulator/touch-simulator.js"></script>
  </head>
  <body>
@ -27,7 +27,7 @@
    <script src="<%= BASE_URL %>js/vconsole.min.js"></script>
    <script>
			// 初始化
			var vConsole = new VConsole();
			// var vConsole = new VConsole();
		</script> 
  </body>
</html>

+ 1 - 0
mini-pro-web/public/version.txt

@ -0,0 +1 @@
1.0.3

BIN
mini-pro-web/public/versions/1.0.3.jar


+ 128 - 16
mini-pro-web/src/api/api-medicineAbinet.js

@ -5,7 +5,7 @@ let service = {
	//备货单相关接口 start
	//备药单相关接口 start
	replenishList: function(params) {
		return request({
			url: `${BASE}/baseUp/docFullInfo`,
@ -48,7 +48,7 @@ let service = {
			params
		});
    },
	// 生成备货单
	// 生成备药单
	baseUpCreateUp: function(data) {
		return request({
			url: `${BASE}/baseUp/createUp`,
@ -71,7 +71,7 @@ let service = {
			params
		});
    },
	//备货单相关接口 end
	//备药单相关接口 end
	//出库单相关接口 start
@ -193,7 +193,7 @@ let service = {
			data
		});
    },
	// 获取缺货列表
	// 获取缺药列表
	getOutOfStockDeviceList: function(params) {
		return request({
			url: `${BASE}/baseDevice/getOutOfStockDeviceList`,
@ -201,7 +201,7 @@ let service = {
			params
		});
    },
	// 获取缺货信息
	// 获取缺药信息
	getDetialOutOfStock: function(data) {
		return request({
			url: `${BASE}/baseDevice/getDetialOutOfStock`,
@ -424,7 +424,34 @@ let service = {
	// 根据用户id,查询设备在线统计
	countAllDevice: function(params) {
		return request({
			url: `${BASE}/baseDevice/countAllDevice`,
			url: `${BASE}/baseDevice/getFirstPageInfo`,
			method: "get",
			params
		});
    },
    // 根据用户id,天数,查询设备取药次数
	getmedicine: function(params) {
		return request({
			url: `${BASE}/baseDevice/getShippingTypeByUserId`,
			method: "get",
			params
		});
    },
    // 根据用户id,天数,查询设备电子处方单次数
	getprescriptions: function(params) {
		return request({
			url: `${BASE}/baseDevice/getPrescriptionStaticsByUserId`,
			method: "get",
			params
		});
    },
    // 根据用户id,天数,查询销售额
	getechartsData: function(params) {
		return request({
			url: `${BASE}/baseDevice/getDevicePriceStatisticsByUserId`,
			method: "get",
			params
		});
@ -439,7 +466,7 @@ let service = {
		});
    },
	// 更换商品,或者设定商品
	// 更换药品,或者设定药品
	updateMediicinecabineInventory: function(data) {
		return request({
			url: `${BASE}/baseDevice/updateMediicinecabineInventory`,
@ -457,7 +484,7 @@ let service = {
		});
    },
	// 矫正库存\\ 更新容量 \\下架商品
	// 矫正库存\\ 更新容量 \\下架药品
	updateMediicinecabineInventoryInfoById: function(data) {
		return request({
			url: `${BASE}/baseDevice/updateMediicinecabineInventoryInfoById`,
@ -466,7 +493,7 @@ let service = {
		});
    },
	// 通过userId, 获取缺货列表
	// 通过userId, 获取缺药列表
	getOutOfStockDeviceListByUserId: function(params) {
		return request({
			url: `${BASE}/baseDevice/getOutOfStockDeviceListByUserId`,
@ -536,13 +563,13 @@ let service = {
    },
    // 获取设备携带不同类型的日志的二级树,补货日志、换货日志、上货日志
	getDeviceInventoryRecordListWithUserId: function(params) {
		return request({
			url: `${BASE}/baseDevice/getDeviceInventoryRecordListWithUserId`,
			method: "get",
			params
		});
    },
	// getDeviceInventoryRecordListWithUserId: function(params) {
	// 	return request({
	// 		url: `${BASE}/baseDevice/getDeviceInventoryRecordListWithUserId`,
	// 		method: "get",
	// 		params
	// 	});
    // },
	findOrgList(params){
@ -560,7 +587,92 @@ let service = {
			params: data
		});
	},
	//获取所有设备最后一次补货记录
	getDeviceInventoryRecordListWithUserId: function(data) {
		return request({
			url: `${BASE}/baseDevice/getDeviceInventoryRecordListWithUserId`,
			method: "get",
			params: data
		});
	},
	//获取单个设备的补货记录
	getDeviceInventoryRecordListByDeviceId: function(data) {
		return request({
			url: `${BASE}/baseDevice/getDeviceInventoryRecordListByDeviceId`,
			method: "get",
			params: data
		});
	},
	// 通过设备id获取该设备的缺药信息
	getOutOfStockInfoByDeviceWithPage: function(data) {
		return request({
			url: `${BASE}/baseDevice/getOutOfStockInfoByDeviceWithPage`,
			method: "get",
			params: data
		});
	},
	// 以药品为维度的药品库存统计
	getDrugInventoryCount: function(params) {
		return request({
			url: `${BASE}/baseDevice/getDrugInventoryCount`,
			method: "get",
			params
		});
    },
	//根据用户和设备获取出货单详情
	getOutDetailByUserIdAndDeviceId: function(params) {
		return request({
			url: `${BASE}/baseOut/getOutDetailByUserIdAndDeviceId`,
			method: "get",
			params
		});
    },
	// 批量补货
	batchAddInventory: function(data) {
		return request({
			url: `${BASE}/baseDevice/batchAddInventory`,
			method: "post",
			data
		});
    },
	
	//设备出货日志
	getDeviceOrderInfoPage: function(params) {
		return request({
			url: `${BASE}/baseDevice/getDeviceOrderInfoPage`,
			method: "get",
			params
		});
    },
	queryUpListByDeviceIdAndStatus: function(params) {
		return request({
			url: `${BASE}/baseUp/queryUpListByDeviceIdAndStatus`,
			method: "get",
			params
		});
    },
	queryUpListByStatus: function(params) {
		return request({
			url: `${BASE}/baseUp/queryUpListByStatus`,
			method: "get",
			params
		});
    },
	updateStockUpStatus: function(data) {
		return request({
			url: `${BASE}/baseUp/updateStockUpStatus`,
			method: "post",
			data
		});
    },
};
export default service;

+ 47 - 0
mini-pro-web/src/api/login.js

@ -126,6 +126,45 @@ export function findOneUser(data) {
	});
}
export function findOneUserFormat(data) {
    return new Promise((resolve, reject)=>{
		request({
			url: `${BASE}/user/queryOne`,
			method: "get",
			params: data
		})
		.then(res=>{
			if(res && res.obj){
				// "saasAdmin": "管理员"; regionAdmin" "区域管理员" ; communityAdmin "社区管理员" ;  "  "replenisher": "补货员"
				var temArr = ['saasAdmin', 'regionAdmin', 'communityAdmin', 'replenisher']
				var role = res.obj.role instanceof Array? res.obj.role : [res.obj.role]
				var roleList = _.map(role, v=>{
					return {
						id: v.id,
						code: v.code,
						name: v.name
					}
				})
				roleList = _.sortBy(roleList, v=>{
					return temArr.indexOf(v.code)
				})
				var curRole = roleList[0]
				var userInfo = {
					roleList,
					curRoleId: curRole.id,
					curRoleCode: curRole.code,
					curRoleName: curRole.name
				}
				resolve(userInfo)
			}
		})
		.catch(err=>{
			reject(err)
		})
	})
}
export function changePwd(data) {
	return request({
	  url: `${BASE}/user/updatePwd`,
@ -140,4 +179,12 @@ export function checkWlyyLogin(data) {
	  method: 'post',
	  data
	})
}
export function findLoginRoleMenuTree(data) {
	return request({
		url: `${BASE}/menu/findLoginRoleMenuTree`,
		method: "get",
		params: data
	});
}

BIN
mini-pro-web/src/assets/images/Waiting-medicine.png


BIN
mini-pro-web/src/assets/images/beihuo.png


BIN
mini-pro-web/src/assets/images/beihuojilu.png


BIN
mini-pro-web/src/assets/images/buhuo.png


BIN
mini-pro-web/src/assets/images/buhuojilu.png


BIN
mini-pro-web/src/assets/images/chufangdan_img.png


BIN
mini-pro-web/src/assets/images/chufangdan_img_01.png


BIN
mini-pro-web/src/assets/images/diandanguanli01_icon.png


BIN
mini-pro-web/src/assets/images/diandanguanli_icon.png


BIN
mini-pro-web/src/assets/images/drug.png


BIN
mini-pro-web/src/assets/images/equipment.png


BIN
mini-pro-web/src/assets/images/offline-equipment.png


BIN
mini-pro-web/src/assets/images/offline-medicine.png


BIN
mini-pro-web/src/assets/images/order.png


BIN
mini-pro-web/src/assets/images/peitu_img.png


BIN
mini-pro-web/src/assets/images/quyaochishu_img.png


BIN
mini-pro-web/src/assets/images/quyaocishu_img.png


BIN
mini-pro-web/src/assets/images/replenishment.png


BIN
mini-pro-web/src/assets/images/shebeigaikuang_img.png


BIN
mini-pro-web/src/assets/images/shebeigaunli01_icon.png


BIN
mini-pro-web/src/assets/images/shebeigaunli_icon.png


BIN
mini-pro-web/src/assets/images/temperature.png


BIN
mini-pro-web/src/assets/images/thermometer.png


BIN
mini-pro-web/src/assets/images/waiting-equipment.png


BIN
mini-pro-web/src/assets/images/yaopingaikuang.png


+ 29 - 3
mini-pro-web/src/assets/styles/index.scss

@ -3,10 +3,25 @@
@import '../../../public/js/vant/vantExt.css';
@import './resetVant.scss';
* {
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    box-sizing: border-box;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
  -webkit-touch-callout:none; /*系统默认菜单被禁用*/
  -webkit-user-select:none; /*webkit浏览器*/
  -khtml-user-select:none; /*早期浏览器*/
  -moz-user-select:none;/*火狐*/
  -ms-user-select:none; /*IE10*/
  user-select:none;
}
input,textarea {
  -webkit-user-select:auto; /*webkit浏览器*/
  margin: 0px;
  padding: 0px;
  outline: none;
}
body {
  height: 100%;
  -moz-osx-font-smoothing: grayscale;
@ -41,6 +56,14 @@ html {
  font-size : 16px;
}
@supports(bottom: env(safe-area-inset-bottom)){
  .custom-list{
    .van-list__placeholder{
      margin-bottom: env(safe-area-inset-bottom);
    }
  }
}
@media only screen and (max-width: 361px){
  html {
      font-size: 14px !important;
@ -49,6 +72,9 @@ html {
#app{
  height: 100%;
}
.over-hidden{
  overflow: hidden;
}
// *,
// *:before,

+ 50 - 8
mini-pro-web/src/components/ProductItem/index.vue

@ -1,40 +1,65 @@
<template>
    <div @click="toSet" class='components-product-item' :class="{'pitem-full':data.cargoCapacity==data.qty, 'pitem-close': data.cargoState!=1, 'pitem-fault': data.faultState==1}">
    <div @click="toSet" class='components-product-item' 
        :class="{'pitem-full':data.cargoCapacity==data.qty, 'pitem-close': data.cargoState!=1, 'pitem-fault': data.faultState==1, 'pitem-active': isActive, 'pitem-main': data.state==21}">
        <div :style="'height: '+ (rate) +'%'" class="pitem-bg"></div>
        <div class="pitem-inner" >
            <div class="kitbox " >
                <div class="box-flex-1">{{index+1}}号位</div>
                <div class="box-flex-1">{{wayerNo}}号位</div>
                <div>{{data.qty}}/{{data.cargoCapacity}}</div>
            </div>
            <template v-if="data.shelfStatus==1">
                <div class="ellipsis tc pt8">{{data.drugName}}</div>
                <div class="tc pt5">¥{{data.price}}</div>
                <div class="ellipsis tc pt12">{{data.drugName}}</div>
                <div class="ellipsis tc pt10">{{data.specif}}</div>
            </template>
            <div v-else class="ellipsis tc pt8 ">未设商品</div>
            <div v-else class="ellipsis tc pt12 ">未设药品</div>
        </div>
        <div class="tag" v-if="data.state==21">主</div>
        <div class="tag" v-else-if="data.state==20">副</div>
        <img class="gouxuan" src="@/assets/images/gouxuan.png" alt="">
    </div>
</template>
<script>
export default{
    props: ['data', 'index'],
    props: ['data', 'index', 'bussuness', 'isView'],//bussuness quick快速补货  isView
    data(){
        return {
            
            isActive: false
        }
    },
    computed:{
        wayerNo(){
            if(this.data.state==21){
                var arr = this.data.merge.split(",")
                return arr[0] + '~' + arr[arr.length-1]
            }
            return this.data.wayerNo
        },
        rate(){
            var {data} = this
            return (data.qty||0) / (data.cargoCapacity||5) * 100
        },
    },
    watch: {
        'data.isActive':{
            handler(n){
                this.isActive = n
            },
            deep: true
        }
    },
    created() {
        
        this.isActive = this.data.isActive
    },
    methods:{
        toSet(){
            if(this.isView){
                return
            }
            if(this.bussuness == 'quick'){
                this.isActive = !this.isActive
                this.$emit('onChange', this.isActive)
                return
            }
            if(this.data.state==20){
                this.$toast('不能操作副通道,如要修改请修改它的主通道')
                return
@ -74,6 +99,7 @@ export default{
        position: relative;
        z-index: 1;
        background: transparent;
        line-height: 1.2;
    }
    .pitem-bg{
        background: #17b3ec;
@ -112,5 +138,21 @@ export default{
            display: none;
        }
    }
    .gouxuan{
        position: absolute;
        right: 0;
        bottom: 0;
        width: 20px;
        display: none;
    }
    &.pitem-active{
        border: 1px solid red;
        .gouxuan{
            display: block;
        }
    }
    &.pitem-main{
        width: 280px!important;
    }
}
</style>

+ 6 - 2
mini-pro-web/src/components/layout/NavLayout.vue

@ -9,7 +9,7 @@
			@click-left="onClickLeft"
			>
		</van-nav-bar>
		<div class="main-container" :class="{pt46:hasTop, mainNobotHasTop: hasTop, 'has-bot': hasBot}">
		<div class="main-container" :class="{pt46:hasTop, mainNobotHasTop: hasTop, 'has-bot': hasBot, 'iphone-x': isIphonex}">
			<app-main/>
		</div>
		<AppBotNav v-if="hasBot"></AppBotNav>
@ -18,7 +18,7 @@
<script>
import { AppMain, AppBotNav } from "./components";
import iphoneUtils from  "@/utils/iphoneUtils"
export default {
	name: "NavLayout",
	components: {
@ -45,6 +45,10 @@ export default {
	computed: {
		title() {
			return this.$store.state.app.pageTitle
		},
		isIphonex(){
			// return true
			return iphoneUtils.isIphonex()
		}
	},
	methods: {

+ 83 - 24
mini-pro-web/src/components/layout/components/AppBotNav.vue

@ -1,22 +1,23 @@
<template>
  	<div class="app-bot-nav">
		<van-row type="flex">
			<van-col class="flex1">
				<div @click="toUrl(0)" class="app-bot-nav-item " :class="{active: active===0}">
			<van-col v-for="(item, i) in urls" :key="i" class="flex1">
				<div @click="toUrl(i)" class="app-bot-nav-item " :class="{active: active===i}">
					<div class="app-bot-nav-item_icon">
						<img class="pre-icon" src="@/assets/images/icon_shouye.png">
						<img class="next-icon" src="@/assets/images/icon_shouye-dianji.png">
						<img class="pre-icon" :src="item.icon1">
						<img class="next-icon" :src="item.icon2">
					</div>
					<div class="">首页</div>
					<div class="">{{item.name}}</div>
				</div>
			</van-col>
			<van-col class="flex1">
			<!-- <van-col class="flex1">
				<div @click="toUrl(1)" class="app-bot-nav-item " :class="{active: active==1}">
					<div class="app-bot-nav-item_icon">
						<img class="pre-icon" src="@/assets/images/xiaoxi_icon.png">
						<img class="next-icon" src="@/assets/images/xiaoxi02_icon.png">
					</div>
					<div class="">补货</div>
					<div class="">订单管理</div>
				</div>
			</van-col>
			<van-col class="flex1">
@ -25,9 +26,18 @@
						<img class="pre-icon" src="@/assets/images/icon_wode.png">
						<img class="next-icon" src="@/assets/images/icon_wode-dianji.png">
					</div>
					<div class="">我的</div>
					<div class="">设备管理</div>
				</div>
			</van-col>
			<van-col class="flex1">
				<div @click="toUrl(3)" class="app-bot-nav-item " :class="{active: active==3}">
					<div class="app-bot-nav-item_icon">
						<img class="pre-icon" src="@/assets/images/icon_wode.png">
						<img class="next-icon" src="@/assets/images/icon_wode-dianji.png">
					</div>
					<div class="">我的</div>
				</div>
			</van-col> -->
		</van-row>
	</div>
</template>
@ -36,17 +46,14 @@
export default {
	name: "AppBotNav",
	data(){
		var urls = [
			{url: "/home/index", count: 0},
			{url: "/replenishment/index", count: 0},
			{url: "/personal/index", count: 0}
		]
		var active = this.check(urls)
		return {
			active,
			urls
			active: 0,
			urls: []
		}
	},
	computed:{
		
    },
	watch:{
		'$route': {
			handler(n, o){
@ -55,16 +62,30 @@ export default {
			immediate: true
		}
	},
	created(){
		var urls = [
			{url: "homeIndex", count: 0, name: "首页", icon1: require('@/assets/images/icon_shouye.png'), icon2: require('@/assets/images/icon_shouye-dianji.png')},
		]
		if(this.$hasAuth('orderManage')){
			urls.push({url: "orderList", count: 0, name: "订单管理", icon1: require('@/assets/images/diandanguanli_icon.png'), icon2: require('@/assets/images/diandanguanli01_icon.png')})
		}
		if(this.$hasAuth('device', 'operate')){
			urls.push({url: "deviceIndex", count: 0, name: "设备管理", icon1: require('@/assets/images/shebeigaunli_icon.png'), icon2: require('@/assets/images/shebeigaunli01_icon.png')})
		}
		urls.push({url: "personalIndex", count: 0, name: "我的", icon1: require('@/assets/images/icon_wode.png'), icon2: require('@/assets/images/icon_wode-dianji.png')})
		
		var active = this.check(urls)
		this.urls = urls
		this.active = active
	},
	mounted(){
		
	},
	computed:{
    },
	
	methods: {
		check(urls){
			urls = urls || this.urls
			var p = this.$route.path
			var p = this.$route.name
			var index = -1
			urls.forEach((v, i) => {
@ -78,10 +99,44 @@ export default {
			this.active = type;
			let url = this.urls[this.active].url
			if(url){
				this.$router.replace({
					path: url
				})
				if(this.$route.name == 'homeIndex'){
					this.$router.push({
						name: url
					})
				} else {
					if(url == 'homeIndex'){
						var exist = _.find(this.$navigation.getRoutes(), v=>{
							return v.indexOf(url+'?') === 0
						})
						if(exist){
							exist = exist.split('?')
							url = this.replaceCamel(exist[0])
							if(url.indexOf('/')!==0){
								url = "/" + url
							}
							this.$router.replace({
								path: url,
								query: {
									VNK: exist[1]
								}
							})
						} else {
							this.$router.replace({
								name: url
							})
						}
					} else {
						this.$router.replace({
							name: url
						})
					}
				}
			}
		},
		replaceCamel(str){
			return str.replace(/([A-Z])/g, function(s){
				return '/' +s.toLowerCase()
			}).trim()
		}
	}
};
@ -90,5 +145,9 @@ export default {
@import '../styles/appBotNav.scss';
</style>
<style lang="scss">
@supports(bottom: env(safe-area-inset-bottom)){
    .app-bot-nav{
        padding-bottom: env(safe-area-inset-bottom);
    }
}
</style>

+ 5 - 1
mini-pro-web/src/components/layout/components/AppMain.vue

@ -61,5 +61,9 @@ export default {
}
</style>
<style lang="scss">
@supports(bottom: env(safe-area-inset-bottom)){
    .app-main{
        padding-bottom: env(safe-area-inset-bottom);
    }
}
</style>

+ 2 - 1
mini-pro-web/src/components/layout/styles/appBotNav.scss

@ -1,5 +1,5 @@
.app-bot-nav{
    height: 50px;
    // height: 50px;
    border-top: 1px solid #e1e1e1;
    background: #fff;
    position: fixed; 
@ -8,6 +8,7 @@
    z-index: 2;
    .app-bot-nav-item{
        padding-top: 7px;
        padding-bottom: 3px;
        text-align: center;
        color: #c8c8c8;
        font-size: 12px;

+ 55 - 0
mini-pro-web/src/directive/longpress.js

@ -0,0 +1,55 @@
//长按指令
export default {
    install(Vue, options = {
      time: 800
    }) {
      Vue.directive('longpress', {
        bind: function(el, binding, vNode) {
            console.log("longpress")
          // 确保提供的表达式是函数
          if (typeof binding.value !== 'function') {
            // 获取组件名称
            const compName = vNode.context.name;
            // 将警告传递给控制台
            let warn = `[longpress:] provided expression '${binding.expression}' is not afunction, but has to be `;
            if (compName) { warn += `Found in component '${compName}' `}
            console.warn(warn);
          }
          // 定义变量
          let pressTimer = null;
          // 定义函数处理程序
          // 创建计时器( 1秒后执行函数 )
          let start = (e) => {
            if (e.type === 'click' && e.button !== 0) {
              return;
            }
            if (pressTimer === null) {
              pressTimer = setTimeout(() => {
                // 执行函数
                handler(e);
              }, options.time)
            }
          }
          // 取消计时器
          let cancel = (e) => {
            // 检查计时器是否有值
            if ( pressTimer !== null ) {
              clearTimeout(pressTimer);
              pressTimer = null;
            }
          }
          // 运行函数
          const handler = (e) => {
            // 执行传递给指令的方法
            binding.value(e)
          };  
          // 添加事件监听器
          el.addEventListener("touchstart", start);
          // 取消计时器
          el.addEventListener("touchend", cancel);
          el.addEventListener("touchmove", cancel);
          el.addEventListener("touchcancel", cancel);
        }
      })
    }
  }

+ 3 - 0
mini-pro-web/src/main.js

@ -36,6 +36,9 @@ Vue.use(CustomComponents)
import CustomUpload from '@/components/CustomUpload'
Vue.component("CustomUpload", CustomUpload)
import longpress from '@/directive/longpress'
Vue.use(longpress)
new Vue({
	data: {
		imWs: null,

+ 25 - 0
mini-pro-web/src/mixins/common.js

@ -188,6 +188,31 @@ Vue.mixin({
                };
            };
            return fmt;
        },
        $hasAuth(url, url1, url2){
            function func(list, name, isLeaf){
                var e = _.find(list, v=>{
                    return v.url == name
                })
                return isLeaf? e : ((e&&e.children) || '')
            }
            var temp = func(this.$store.state.app.authMenu, url)
            if(!temp){
                return ''
            }
            if(!url1){
                return temp
            } 
            temp = func(temp, url1)
            if(!temp){
                return ''
            }
            if(!url2){
                return temp
            } 
            return func(temp, url2, true)
        }
    }
})

+ 16 - 5
mini-pro-web/src/router/device.js

@ -13,8 +13,8 @@ const device = [
                component: () => import('@/views/device/index.vue'),
                meta: {
                    title: '设备管理',
                    hasBot: false,
                    // hasTop: false
                    hasBot: true,
                    hasTop: false
                }
            },
            {
@ -22,11 +22,22 @@ const device = [
                name: "deviceDetail",
                component: () => import('@/views/device/detail.vue'),
                meta: {
                    title: '设备',
                    title: '设备详情',
                    hasBot: false,
                    // hasTop: false
                }
            },
            {
                path: "/device/stock",
                name: "deviceStock",
                component: () => import('@/views/device/stock.vue'),
                meta: {
                    title: '药品概况',
                    hasBot: false,
                    // hasTop: false
                }
            },
            
            {
                path: "/device/temperature/index",
                name: "temperatureIndex",
@ -82,7 +93,7 @@ const device = [
                name: "cargoLaneSetting",
                component: () => import('@/views/device/cargoLane/setting.vue'),
                meta: {
                    title: '货道状态',
                    title: '货道设置',
                    hasBot: false,
                    // hasTop: false
                }
@ -122,7 +133,7 @@ const device = [
                name: "deviceSell",
                component: () => import('@/views/device/sell.vue'),
                meta: {
                    title: '在售停售',
                    title: '维护/上架',
                    hasBot: false,
                    // hasTop: false
                }

+ 96 - 33
mini-pro-web/src/router/index.js

@ -10,15 +10,16 @@ import Login from '@/views/login/Login'
import Register from '@/views/login/Register'
import FotgetPassword from '@/views/login/FotgetPassword'
import DrugList from '@/views/drug/list'
import Index from '@/views/index/Index'
import personal from './personal'
import order from './order'
import replenishment from './replenishment'
import device from './device'
import machine from './machine'
import {getPublicKey, getHwlyyDecrypt, checkWlyyLogin} from '@/api/login'
import {getPublicKey, getHwlyyDecrypt, checkWlyyLogin, findOneUserFormat} from '@/api/login'
import JSEncrypt from "@/utils/jsencrypt";
import { Toast } from 'vant'
import { findLoginRoleMenuTree } from '@/api/login'
import { _ } from 'core-js'
Vue.use(VueRouter)
const routes = [
@ -64,7 +65,7 @@ const routes = [
        children: [{
            path: "index",
            name: "homeIndex",
            component: Index,
            component: () => import('@/views/index/Index'),
            meta: {
                title: '首页',
                hasBot: true,
@ -112,8 +113,26 @@ function redirectToLogin(to, from, next) {
    }
}
var routerLoaded = false
function formatAuthMenu(menu){
    if(menu){
        return _.map(menu, v=>{
            return {
                name: v.name,
                url: v.url,
                type: v.type,
                children: v.children? formatAuthMenu(v.children) : []
            }
        })
    }
}
router.beforeEach(async (to, from, next) => {
    // _from=ihealth&_platform=webApp
    if(!to.query.VNK){
        //因为引入navigation组件  beforeEach会执行两次 第一次无VNK 第二次为设置VNK值  所以当VNK不存在时 直接跳过
        next()
        return
    }
    if(to.query._noTop==1){
        store.dispatch('SetNoTop', true)
    }
@ -130,8 +149,37 @@ router.beforeEach(async (to, from, next) => {
    })
    .then(res=>{
        if((store.getters.user && store.getters.user.accessToken)) {
            next()
            if(!routerLoaded){
                findOneUserFormat({
                    id: store.getters.user.id
                }).then(userInfo2 => {
                    var userInfo = _.assignIn(store.getters.user, userInfo2);
                    store
                        .dispatch('SetLoginUser', userInfo)
                        .then(res=>{
                            findLoginRoleMenuTree({
                                roleId: store.getters.user.curRoleId
                            })
                            .then(res=>{
                                routerLoaded = true
                                var routeList = formatAuthMenu(res.detailModelList)
                                store.dispatch('SetAuthMenu', routeList)
                                console.log('routeList', routeList)
                                next()
                            })
                            .catch(err=>{
                                console.error(err)
                            })
                        })
                }).catch(err=>{
                    routerLoaded = true
                    console.error(err)
                })
            } else {
                next()
            }
        } else {
            routerLoaded = false
            if( whiteList.indexOf(to.path) > -1) {
                next()
            } else {
@ -177,34 +225,47 @@ function authLogin(code, to){
                    var userInfo  = res.obj.WlyyUserSimple
                    userInfo.token = userInfo.accessToken
                    userInfo.clientType = to.query.clientType//1 来自i健康app 区域互联网
                    // "saasAdmin": "管理员"; regionAdmin" "区域管理员" ; communityAdmin "社区管理员" ;  "  "replenisher": "补货员"
                    // 18补货员 19社区管理员 20区域管理员 21超管
                    var dictList = {
                        18: {
                            curRoleCode: "replenisher",
                            curRoleName: "补货员"
                        },
                        19: {
                            curRoleCode: "communityAdmin",
                            curRoleName: "社区管理员"
                        },
                        20: {
                            curRoleCode: "regionAdmin",
                            curRoleName: "区域管理员"
                        },
                        21: {
                            curRoleCode: "saasAdmin",
                            curRoleName: "管理员"
                        },
                    }
                    var { curRoleCode, curRoleName } = dictList[to.query._role]
                    userInfo.curRoleCode = curRoleCode
                    userInfo.curRoleName = curRoleName
                    store
                        .dispatch('SetLoginUser', userInfo)
                        .then(res=>{
                            resolve()
                        })
                    store.dispatch('SetLoginUser', userInfo)
                    findOneUserFormat({
                        id: userInfo.id
                    }).then(userInfo2 => {
                        userInfo = _.assignIn(userInfo, userInfo2);
                        store
                            .dispatch('SetLoginUser', userInfo)
                            .then(res=>{
                                resolve()
                            })
                    }).catch(err=>{
                        console.error(err)
                    })
                    // // "saasAdmin": "管理员"; regionAdmin" "区域管理员" ; communityAdmin "社区管理员" ;  "  "replenisher": "补货员"
                    // // 18补货员 19社区管理员 20区域管理员 21超管
                    // var dictList = {
                    //     18: {
                    //         curRoleCode: "replenisher",
                    //         curRoleName: "补货员"
                    //     },
                    //     19: {
                    //         curRoleCode: "communityAdmin",
                    //         curRoleName: "社区管理员"
                    //     },
                    //     20: {
                    //         curRoleCode: "regionAdmin",
                    //         curRoleName: "区域管理员"
                    //     },
                    //     21: {
                    //         curRoleCode: "saasAdmin",
                    //         curRoleName: "管理员"
                    //     },
                    // }
                    // var { curRoleCode, curRoleName } = dictList[to.query._role]
                    // userInfo.curRoleCode = curRoleCode
                    // userInfo.curRoleName = curRoleName
                    // store
                    //     .dispatch('SetLoginUser', userInfo)
                    //     .then(res=>{
                    //         resolve()
                    //     })
                } else {
                    Toast(res.message|| (res.obj&&res.obj.mes))
                    reject(res)
@ -232,4 +293,6 @@ router.afterEach((to, from) => {
    window.scrollTo(0, 0);
})
export default router

+ 2 - 2
mini-pro-web/src/router/order.js

@ -10,8 +10,8 @@ const routeMap = [
                name: "orderList",
                meta: {
                    title: "订单管理",
                    // hasTop: false,
                    hasBot: false
                    hasTop: false,
                    hasBot: true
                },
				component: () => import("@/views/order/list.vue")
            },

+ 53 - 11
mini-pro-web/src/router/replenishment.js

@ -19,7 +19,7 @@ const routeMap = [
                path: "/replenishment/device/list",
                name: "replenishmentDeviceList",
                meta: {
                    title: "设备商品概况",
                    title: "设备药品概况",
                    // hasTop: false,
                    hasBot: false
                },
@ -29,7 +29,7 @@ const routeMap = [
                path: "/replenishment/device/detail",
                name: "replenishmentDeviceDetail",
                meta: {
                    title: "设备商品概况",
                    title: "设备药品概况",
                    // hasTop: false,
                    hasBot: false
                },
@ -39,7 +39,7 @@ const routeMap = [
                path: "/replenishment/record/list",
                name: "replenishmentRecordList",
                meta: {
                    title: "补货记录",
                    title: "入库记录",
                    // hasTop: false,
                    hasBot: false
                },
@ -49,7 +49,7 @@ const routeMap = [
                path: "/replenishment/record/detail",
                name: "replenishmentRecordDetail",
                meta: {
                    title: "补货记录详情",
                    title: "入库记录详情",
                    // hasTop: false,
                    hasBot: false
                },
@ -59,17 +59,27 @@ const routeMap = [
                path: "/replenishment/picking/list",
                name: "replenishmentPickingList",
                meta: {
                    title: "备货单",
                    title: "药品申领详情",
                    // hasTop: false,
                    hasBot: false
                },
				component: () => import("@/views/replenishment/picking/list.vue")
            },
            {
                path: "/replenishment/picking/outList",
                name: "replenishmentOutList",
                meta: {
                    title: "出库单列表",
                    // hasTop: false,
                    hasBot: false
                },
				component: () => import("@/views/replenishment/picking/outList.vue")
            },
            {
                path: "/replenishment/picking/detail",
                name: "replenishmentPickingDetail",
                meta: {
                    title: "备货单详情",
                    title: "药品申领详情",
                    // hasTop: false,
                    hasBot: false
                },
@ -79,7 +89,7 @@ const routeMap = [
                path: "/replenishment/stockUp/deviceList",
                name: "replenishmentStockUpDeviceList",
                meta: {
                    title: "查看缺货设备",
                    title: "查看缺药设备",
                    // hasTop: false,
                    hasBot: false
                },
@ -89,12 +99,34 @@ const routeMap = [
                path: "/replenishment/stockUp/detail",
                name: "replenishmentStockUpDetail",
                meta: {
                    title: "查看缺货汇总",
                    title: "查看缺药汇总",
                    // hasTop: false,
                    hasBot: false
                },
				component: () => import("@/views/replenishment/stockUp/detail.vue")
            },
            {
                path: "/replenishment/stockUp/createOut",
                name: "replenishmentStockUpCreateOut",
                meta: {
                    title: "生成出药单",
                    // hasTop: false,
                    hasBot: false
                },
				component: () => import("@/views/replenishment/stockUp/createOut.vue")
            },
            {
                path: "/replenishment/stockUp/drugList",
                name: "ReplenishmentDrugSel",
                meta: {
                    title: "选择药品",
                    // hasTop: false,
                    hasBot: false
                },
				component: () => import("@/views/replenishment/stockUp/drugList.vue")
            },
            
            {
                path: "/replenishment/start/deviceList",
@ -110,17 +142,27 @@ const routeMap = [
                path: "/replenishment/start/deviceDetail",
                name: "replenishmentStartDeviceDetail",
                meta: {
                    title: "补货",
                    title: "药品入库",
                    // hasTop: false,
                    hasBot: false
                },
				component: () => import("@/views/replenishment/start/deviceDetail.vue")
            },
            {
                path: "/replenishment/start/quick",
                name: "replenishmentStartQuick",
                meta: {
                    title: "药品详情",
                    // hasTop: false,
                    hasBot: false
                },
				component: () => import("@/views/replenishment/start/quick.vue")
            },
            {
                path: "/replenishment/start/productDetail",
                name: "replenishmentStartProductDetail",
                meta: {
                    title: "商品详情",
                    title: "药品详情",
                    // hasTop: false,
                    hasBot: false
                },
@ -130,7 +172,7 @@ const routeMap = [
                path: "/replenishment/start/selProduct",
                name: "replenishmentStartSelProduct",
                meta: {
                    title: "选择商品",
                    title: "选择药品",
                    // hasTop: false,
                    hasBot: false
                },

+ 1 - 1
mini-pro-web/src/store/getters.js

@ -1,7 +1,7 @@
const getters = {
    loading: state => state.app.loading,
    pageTitle: state => state.app.pageTitle,
    clientId: state => "EwC0iRSrcS",
    clientId: state => "EwC0iRSrcSApp",
    user: state => state.user,
    wxAppId: state => state.app.wxWechatConfig && state.app.wxWechatConfig.wxAppId,
    wxId: state => state.app.wxWechatConfig && state.app.wxWechatConfig.wxId,

+ 5 - 2
mini-pro-web/src/store/index.js

@ -7,10 +7,13 @@ Vue.use(Vuex)
export default new Vuex.Store({
	state: {
		loading: true
        loading: true,
        deviceActive:1,
	},
	mutations: {
        getDeviceActive(state,payload){
            state.deviceActive = payload
        }
	},
	actions: {
		

+ 16 - 2
mini-pro-web/src/store/modules/app.js

@ -6,9 +6,11 @@ const app = {
			wxId: process.env.VUE_APP_WXID
        },
        loading: false,
        pageTitle: "智能药房",
        pageTitle: "智慧药房",
		platform: 'web',  //网页web   
		noTop: false
		noTop: false,
		authMenu: [],
		drugList: []
	},
	mutations: {
		SET_NO_TOP: (state, bool) => {
@ -19,6 +21,12 @@ const app = {
		},
		SET_PAGE_TITLE: (state, val) => {
            state.pageTitle = val
        },
		SET_AUTH_MENU: (state, val) => {
            state.authMenu = val
        },
		SET_DRUG_LIST: (state, val) => {
            state.drugList = val
        }
	},
	actions: {
@ -30,6 +38,12 @@ const app = {
		},
		SetPageTitle({ commit, state }, val) {
			commit('SET_PAGE_TITLE', val)
		},
		SetAuthMenu({ commit, state }, val) {
			commit('SET_AUTH_MENU', val)
		},
		SetDrugList({ commit, state }, val) {
			commit('SET_DRUG_LIST', val)
		}
	}
};

+ 3 - 1
mini-pro-web/src/store/modules/user.js

@ -14,7 +14,9 @@ const user = {
            }
        },
        REMOVE_USER: (state, user) => {
            state.info = {}
            for(var k in state){
                delete state[k]
            }
        },
    },

+ 3 - 0
mini-pro-web/src/utils/navigator/README.md

@ -1,3 +1,6 @@
需注意:
  因为引入navigation组件 router.beforeEach会执行两次 第一次无VNK 第二次为设置VNK值 
需要 vue 2.x 与 vue-router 2.x。
导航默认行为类似手机APP的页面导航(A、B、C为页面):

+ 1 - 1
mini-pro-web/src/views/device/cargoLane/index.vue

@ -36,7 +36,7 @@
            </div>
        </van-sticky>
        <div class='bgc-fff plr10 pt10'>
        <div class='bgc-fff plr10 pt10' v-if="list&&list.length">
            <div class=' c-f14 list'>
                <div class="row row-header">
                    <div v-for='(item, i) in list[0].list' :key="i" class='c-t-center w50 ptb10 bgc-ccc' >{{i+1}}</div>

+ 51 - 3
mini-pro-web/src/views/device/cargoLane/setting.vue

@ -89,6 +89,8 @@ export default{
                        var list = _.map(res.detailModelList, v=>{
                            var key = _.keys(v)[0]
                            v[key].forEach(m => {
                                m.layerNo = Number(m.layerNo)
                                m.wayerNo = Number(m.wayerNo)
                                m.check = false
                            });
                            return {
@ -131,7 +133,6 @@ export default{
            }
        },
        onSelectCol(item){
            debugger
            var i = this.selectList.indexOf(item)
            if(i != -1){
                var exist = _.filter(this.selectList, v=>{
@ -171,10 +172,50 @@ export default{
                this.selectList = []
            }
        },
        mergeAndSplitCargo(isMerge){
        checkMerge(){
            return new Promise((resolve, reject)=>{
                var exist = _.find(this.selectList, v=>{
                    return !!v.drugCode
                })
                if(exist){
                    this.$toast.clear()
                    this.$dialog.confirm({
                        message: '当前合并货道存在药品,需把药品下架并取出,如您继续合并默认下架全部药品',
                        confirmButtonText: '继续合并'
                    })
                    .then(() => {
                        this.$loading('保存中..')
                        resolve(true)
                    })
                    .catch(() => {
                        this.$loading('保存中..')
                        resolve(false)
                    });
                    return 
                }
                resolve(true)
            })
        },
        checkSplit(){
            return new Promise((resolve, reject)=>{
                this.$toast.clear()
                this.$dialog.confirm({
                    message: '货道拆分后请取下货道上的药品',
                    confirmButtonText: '继续拆分'
                })
                .then(() => {
                    resolve(true)
                })
                .catch(() => {
                    resolve(false)
                });
            })
        },
        async mergeAndSplitCargo(isMerge){
            this.$loading('保存中..')
            var ids = []
            if(isMerge){
                console.log(this.selectList, 'this.selectList')
                if(!this.selectList.length || this.selectList.length<2){
                    this.$toast('至少选择两个相邻的货道')
                    return
@ -186,7 +227,9 @@ export default{
                    this.$toast('不能选择已合并的通道')
                    return 
                }
                if(!await this.checkMerge()){
                    return
                }
                var list = _.sortBy(this.selectList, 'wayerNo')
                ids = _.map(list, v=>{
                    return v.id
@ -196,6 +239,10 @@ export default{
                    this.$toast('请选择一个主货道')
                    return
                }
                if(!await this.checkSplit()){
                    return
                }
                this.$loading('保存中..')
                var item = this.selectList[0]
                var list = this.list[Number(item.layerNo)-1].list
                ids.push(item.id)
@ -210,6 +257,7 @@ export default{
            }
            
            var p = {
                userId: this.user.id,
                cargoIds: ids.join(','),
                isMerge
            }

+ 191 - 51
mini-pro-web/src/views/device/detail.vue

@ -1,7 +1,19 @@
<template>
    <div class="deviceDetail">
    <div class="deviceDetail pb10">
        <div class="c-border-tb c-f14 c-999 mt10 plr15 ptb10 bgc-fff">
            <div class="c-f16 c-333">{{info.name}}</div>
            <div class=" kitbox">
                <div class="box-flex-1 fs-16 c-333 ellipsis_1">
                    {{info.equName}}
                </div>
                <div class="pt2 ml10">
                    <van-tag type="success" v-if="info.networkStatus==1">在线</van-tag>
                    <van-tag type="danger" v-else>离线</van-tag>
                    <van-tag type="success" v-if="info.saleStatus==1" class="ml5">在售</van-tag>
                    <van-tag type="danger" v-else class="ml5">停售</van-tag>
                </div>
            </div>
            <div class="mt10">
                <span>设备所属:</span>
                <span>{{info.community}}</span>
@ -10,67 +22,137 @@
                <span>设备编号:</span>
                <span>{{info.equNum}}</span>
            </div>
            <div>
                <span>网<i class="mr2em"></i>络:</span>
                <span>4G</span>
            </div>
            <div>
                <span>售卖状态:</span>
                <span>{{info.saleStatus==1?'在售':info.saleStatus==0?'停售':'故障'}}</span>
            </div>
            <div>
                <span>设备地址:</span>
                <span>{{info.deliveryAddress}}</span>
            </div>
        </div>
        <div class='mt20 grid-4 c-f14 c-333 bgc-fff c-border-tb ptb15'>
            <div class='c-t-center' @click='gotoUrl("/device/temperature/index", {id: $route.query.id})'>
                <div>
                    <van-image class='ability' :src='require("@/assets/images/wendukongzhi.png")'/>
        <div class="mt10 bgc-fff c-border-tb">
            <div class="panel-title">药品管理</div>
            <div class='grid-4 c-f14 c-333 ptb15'>
                <!-- @click='gotoUrl("/device/temperature/index", {id: id})' -->
                <div class='c-t-center' @click='gotoUrl("/device/stock", {deviceId: id})'>
                    <div>
                        <van-image class='ability' :src='require("@/assets/images/yaopingaikuang.png")'/>
                    </div>
                    <div>药品概况</div>
                </div>
                <div>温湿度控制</div>
            </div>
            <!-- <div class='c-t-center' @click='gotoUrl("/device/temperature/index", {id: $route.query.id})'>
                <div>
                    <van-image class='ability' :src='require("@/assets/images/shidukongzhi.png")'/>
                <div v-if="hasAuth('stockUp') || createOutAuth" class='c-t-center' @click='toApplyDrug() '>
                    <div>
                        <van-image class='ability' :src='require("@/assets/images/beihuo.png")'/>
                    </div>
                    <div>药品申领</div>
                </div>
                <div>湿度控制</div>
            </div> -->
            <div class='c-t-center' @click='gotoUrl("/device/cargoLane/index", {deviceId: id})'>
                <div>
                    <van-image class='ability' :src='require("@/assets/images/huodaozhuangtai.png")'/>
                <div v-if="hasAuth('replenish')" class='c-t-center' @click='gotoUrl("/replenishment/start/deviceDetail", {deviceId: id})'>
                    <div>
                        <van-image class='ability' :src='require("@/assets/images/buhuo.png")'/>
                    </div>
                    <div>药品入库</div>
                </div>
                <div>货道状态</div>
            </div>
            <div class='c-t-center' @click='gotoUrl("/device/cargoLane/setting", {deviceId: id})'>
                <div>
                    <van-image class='ability' :src='require("@/assets/images/huodaoshezhi.png")'/>
        </div>
        <div v-if="cargoSettingAuth||temperatureCtrlAuth||cargoStateAuth||putDeviceAuth" class="mt10 bgc-fff c-border-tb">
            <div class="panel-title">设备设置</div>
            <div class='grid-4 c-f14 c-333 ptb15'>
                <div v-if="cargoSettingAuth" class='c-t-center' @click='gotoUrl("/device/cargoLane/setting", {deviceId: id})'>
                    <div>
                        <van-image class='ability' :src='require("@/assets/images/huodaoshezhi.png")'/>
                    </div>
                    <div>货道设置</div>
                </div>
                <div>货道设置</div>
            </div>
            <div class='c-t-center' @click='gotoUrl("/device/status", {id: info.id})'>
                <div>
                    <van-image class='ability' :src='require("@/assets/images/shebeizhuangtai.png")'/>
                <div v-if="temperatureCtrlAuth" class='c-t-center' @click='gotoUrl("/device/temperature/index", {id: $route.query.id})'>
                    <div>
                        <van-image class='ability' :src='require("@/assets/images/wendukongzhi.png")'/>
                    </div>
                    <div>温湿度控制</div>
                </div>
                <div>设备状态</div>
            </div>
            <!-- <div class='c-t-center' @click='gotoUrl("/device/reboot")'>
                <div>
                    <van-image class='ability' :src='require("@/assets/images/shebeichongqi.png")'/>
                <div v-if="cargoStateAuth" class='c-t-center' @click='gotoUrl("/device/cargoLane/index", {deviceId: id})'>
                    <div>
                        <van-image class='ability' :src='require("@/assets/images/huodaozhuangtai.png")'/>
                    </div>
                    <div>货道状态</div>
                </div>
                <div>设备重启</div>
            </div> -->
            <div class='c-t-center' @click='gotoUrl("/device/infoLog/index")'>
                <div>
                    <van-image class='ability' :src='require("@/assets/images/xinxirizhi.png")'/>
                <div v-if="putDeviceAuth" class='c-t-center' @click='gotoUrl("/device/sell", {id: info.id, status: info.saleStatus})'>
                    <div>
                        <van-image class='ability' :src='require("@/assets/images/zaishoutingshou.png")'/>
                    </div>
                    <div>维护/上架</div>
                </div>
                <div>信息日志</div>
                <!-- <div class='c-t-center' @click='gotoUrl("/device/temperature/index", {id: $route.query.id})'>
                    <div>
                        <van-image class='ability' :src='require("@/assets/images/shidukongzhi.png")'/>
                    </div>
                    <div>湿度控制</div>
                </div> -->
                <!-- <div class='c-t-center' @click='gotoUrl("/device/status", {id: info.id})'>
                    <div>
                        <van-image class='ability' :src='require("@/assets/images/shebeizhuangtai.png")'/>
                    </div>
                    <div>设备状态</div>
                </div> -->
                <!-- <div class='c-t-center' @click='gotoUrl("/device/reboot")'>
                    <div>
                        <van-image class='ability' :src='require("@/assets/images/shebeichongqi.png")'/>
                    </div>
                    <div>设备重启</div>
                </div> -->
                <!-- <div class='c-t-center' @click='gotoUrl("/device/infoLog/index")'>
                    <div>
                        <van-image class='ability' :src='require("@/assets/images/xinxirizhi.png")'/>
                    </div>
                    <div>信息日志</div>
                </div> -->
            </div>
            <div class='c-t-center' @click='gotoUrl("/device/sell", {id: info.id, status: info.saleStatus})'>
                <div>
                    <van-image class='ability' :src='require("@/assets/images/zaishoutingshou.png")'/>
        </div>
        <div class="mt10 bgc-fff c-border-tb">
            <div class="panel-title">操作日志</div>
            <div class='grid-4 c-f14 c-333 ptb15'>
                <div class='c-t-center' @click='gotoUrl("/device/infoLog/index", {deviceId: id, equNum: info.equNum})'>
                    <div>
                        <van-image class='ability' :src='require("@/assets/images/xinxirizhi.png")'/>
                    </div>
                    <div>信息日志</div>
                </div>
                <div class='c-t-center' @click='gotoUrl("/replenishment/picking/list", {deviceId: id})'>
                    <div>
                        <van-image class='ability' :src='require("@/assets/images/beihuojilu.png")'/>
                    </div>
                    <div>申领记录</div>
                </div>
                <div class='c-t-center' @click='gotoUrl("/replenishment/record/list", {deviceId: id})'>
                    <div>
                        <van-image class='ability' :src='require("@/assets/images/buhuojilu.png")'/>
                    </div>
                    <div>入库记录</div>
                </div>
                <!-- <div class='c-t-center' @click='gotoUrl("/device/status", {id: info.id})'>
                    <div>
                        <van-image class='ability' :src='require("@/assets/images/shebeizhuangtai.png")'/>
                    </div>
                    <div>设备状态</div>
                </div> -->
                <!-- <div class='c-t-center' @click='gotoUrl("/device/reboot")'>
                    <div>
                        <van-image class='ability' :src='require("@/assets/images/shebeichongqi.png")'/>
                    </div>
                    <div>设备重启</div>
                </div> -->
                <!-- <div class='c-t-center' @click='gotoUrl("/device/infoLog/index")'>
                    <div>
                        <van-image class='ability' :src='require("@/assets/images/xinxirizhi.png")'/>
                    </div>
                    <div>信息日志</div>
                </div>
                <div>在售停售</div>
                <div class='c-t-center' @click='gotoUrl("/device/sell", {id: info.id, status: info.saleStatus})'>
                    <div>
                        <van-image class='ability' :src='require("@/assets/images/zaishoutingshou.png")'/>
                    </div>
                    <div>在售停售</div>
                </div> -->
            </div>
        </div>
    </div>
@ -82,13 +164,40 @@ export default {
    data() {
        return {
            info: {},
            id: this.$route.query.id
            id: this.$route.query.id,
            menuAuth: []
        };
    },
    computed:{
        createOutAuth(){
            return this.$hasAuth('replenishmentMgnt', 'pickingList','createOut')
        },
        cargoSettingAuth(){
            return this.hasAuth('cargoSetting')
        },
        cargoStateAuth(){
            return this.hasAuth('cargoState')
        },
        temperatureCtrlAuth(){
            return this.hasAuth('temperatureCtrl')
        },
        putDeviceAuth(){
            return this.hasAuth('putDevice')
        },
    },
    created() {
        this.findById()
        this.menuAuth = _.find(_.find(this.$store.state.app.authMenu, v=>{
            return v.url == 'device'
        }).children, v=>{
            return v.url == 'operate'
        }).children
        console.log('this.menuAuth', this.menuAuth)
    },
    methods: {
        $refreshData(){
            this.findById()
        },
        findById(){
            this.$loading('加载中..')
            let p = {
@ -104,14 +213,45 @@ export default {
                .catch(err=>{
                    console.error(err)
                })
        },
        hasAuth(name){
            return _.find(this.menuAuth, v=>{
                return v.url == name
            })
        },
        toApplyDrug(){
            if(this.createOutAuth){
                this.gotoUrl("/replenishment/picking/list", {
                    deviceId: this.id,
                    status: 2
                })
            } else {
                this.gotoUrl("/replenishment/stockUp/detail", {
                    deviceId: this.id,
                })
            }
        }
    },
};
</script>
<style scoped lang='scss'>
.deviceDetail {
    .mr2em{
        margin-right: 2em;
    .panel-title{
        position: relative;
        padding: 10px 15px ;
        font-size: 15px;
        &::before{
            content: "";
            display: block;
            position: absolute;
            top: 50%;
            left: 0;
            transform: translateY(-50%);
            height: 15px;
            background: #17b3ec;
            width: 3px;
            border-radius: 3px;
        }
    }
    .grid-4{
        display: grid;

+ 190 - 65
mini-pro-web/src/views/device/index.vue

@ -1,108 +1,233 @@
<template>
    <div class='deviceIndex'>
        <van-sticky :offset-top="offsetTop">
            <van-field
                v-model="searchText"
                center
                clearable
                placeholder="请输入设备名或编号">
                <template #button>
                    <van-button size="small" type="info" @click="onSearch()">搜索</van-button>
                </template>
            </van-field>
        </van-sticky>
        <div class='plr15'>
            <van-swipe-cell class="mt10" v-for='(item, index) in list' :key="index">
                <div class='c-f14 bgc-fff ptb15 c-999 plr10' @click="gotoUrl('/device/detail',{id: item.id})">
                    <div class='f_y_c flex f_x_s'>
                        <span class='c-f16 c-333'>{{item.equName}}</span>
                        <div>
                            <van-tag v-if="item.networkStatus==1" type="success" class='mr10'>{{item.networkStatusName}}</van-tag>
                            <van-tag v-else type="danger" class='mr10'>{{item.networkStatusName}}</van-tag>
<div class='deviceIndex'>
    <van-sticky :offset-top="offsetTop">
        <van-tabs v-model="active">
            <van-tab :name="1" title="全部设备"></van-tab>
            <van-tab :name="0" title="缺药设备"></van-tab>
        </van-tabs>
    </van-sticky>
    <CustomList 
        ref="customList"
        @onLoad="onLoad">
        <div slot="search">
            <form action="/">
                <van-search
                    v-model="searchText"
                    placeholder="搜索"
                    show-action
                    @search="onSearch"
                    shape="round"
                >
                <div slot="action" class="plr5">
                    <van-icon @click="filterShow=true" style="vertical-align: text-bottom;" color="#17b3ec" size="20px" name="filter-o" />
                </div>
                </van-search>
            </form>
        </div>
        <div class="list plr15 pt10">
            <van-checkbox-group v-model="result">
                <div @click="gotoUrl('./detail', {id: item.id})" v-for="(item, i) in list" :key="i" class="item bgc-fff plr15 c-333 fs-14">
                    <div class=" ptb10 kitbox">
                        <div class="box-flex-1 fs-14">
                            {{item.equName}}
                            <!-- <van-checkbox :name="item.id">{{item.equName}}</van-checkbox> -->
                        </div>
                        <div class="">
                            <van-tag type="success" v-if="item.networkStatus==1">在线</van-tag>
                            <van-tag type="danger" v-else>离线</van-tag>
                            <van-tag v-if="item.saleStatus==1" type="success">{{item.saleStatusName}}</van-tag>
                            <van-tag v-else type="danger">{{item.saleStatusName}}</van-tag>
                            <van-tag type="success" v-if="item.saleStatus==1" class="ml5">在售</van-tag>
                            <van-tag type="danger" v-else class="ml5">停售</van-tag>
                            <van-tag type="danger" v-if="item.status===0||item.status==='0'" class="ml5">缺货</van-tag>
                        </div>
                    </div>
                    <div class='mt10'>
                        <span>设备所属:</span>
                        <span>{{item.community}}</span>
                    </div>
                    <div>
                        <span>设备编号:</span>
                        <span>{{item.equNum}}</span>
                    <div class="kitbox ptb10 pr40">
                        <div class="pt2">空置率:</div>
                        <div class="box-flex-1 pt10"><van-progress :percentage="accessKzl(item)" /></div>
                    </div>
                    <div>
                        <span>网<i class='mr2em'></i>络:</span>
                        <span>4G</span>
                    <div class="lh20 ptb10 kitbox">
                        <div class="box-flex-1">
                            <div>已入库药品数量:{{item.shangPinKuCun}}</div>
                            <div>待入库药品数量:{{item.daibushangpinshuliang}}</div>
                            <div>未设药品货道:{{item.weishezhishangpinhuodao}}</div>
                            <!-- <div>设备所属:{{item.community}}</div>
                            <div >设备编号:{{item.equNum}}</div> -->
                            <!-- <div>上次补货时间:{{item.shangyicibuhuoshijian}}</div> -->
                        </div>
                        <div class="fs-20 c-pr">
                            <van-icon name="arrow" />
                        </div>
                    </div>
                </div>
                <!-- <template #right> -->
                    <!-- <van-button square text="解绑" type="danger" class="delete-button" @click='unBind(item)'/> -->
                    <!-- <van-button square text="停售" type="warning" class="delete-button" @click="stopSell(item)"/> -->
                <!-- </template> -->
            </van-swipe-cell>
            </van-checkbox-group>
        </div>
    </div>
    </CustomList>
    <FilterPanel 
        v-model="filterShow" 
        :filterOpts="['community']"
        @onSubmit="onSubmit" 
        :extendList.sync="extendList"
        ref="Filter"/>
</div>
</template>
<script>
import FilterPanel from '@/views/order/components/Filter'
import medicineAbinetApi from '@/api/api-medicineAbinet'
export default{
    name: 'deviceIndex',
    components:{
        FilterPanel
    },
    data(){
        return {
            list: [],
            result: [],
            active: this.$route.query.active||this.$route.query.active===0? Number(this.$route.query.active) : 1,
            networkStatus: this.$route.query.networkStatus,
            
            filterShow: false,
            searchText: '',
            list: []
            selcommunity: '',
            extendList: [{
                    name: '状态',
                    value: this.$route.query.networkStatus==undefined? '' : this.$route.query.networkStatus,
                    opts: [{name: '全部', value: ''},
                        {name: '在线', value: 1},
                        {name: '离线', value: 0},
                    ]
                }
            ]
        }
    },
    created(){
        this.findList();
    watch:{
        active(){
            this.$refs.customList.refresh(true)
        }
    },
    methods:{
        onSearch(){
            this.findList()
        },
        unBind(item){
        },
        stopSell(item){
    created() {
        
    },
    mounted(){
        // community: this.$route.query.hospital,
        // town: this.$route.query.town,
        if(this.$route.query.hospital||this.$route.query.town){
            this.selcommunity = {
                hospitalCode: this.$route.query.hospital||'',
                hospitalName: this.$route.query.hospitalName||'',
                town: this.$route.query.town||'',
                townName: this.$route.query.townName||'',
            }
        }
        this.$refs.Filter.submit(this.selcommunity)
    },
    methods:{
        $refreshData(){
            this.$refs.customList.refresh(true)
        },
        onLoad({page, pageSize, searchText}){
            var community = '', town = '', networkStatus = ''
            if(this.selcommunity){
                community = this.selcommunity.hospitalCode||this.selcommunity.hospital||''
                town = community? '' : (this.selcommunity.town||'')
            }
            debugger
        findList(){
            this.$loading('加载中..')
            this.list = []
            let p = {
            if(this.extendList[0].value!==undefined){
                networkStatus = this.extendList[0].value
            }
            
            var p = {
                networkStatus: networkStatus,
                content: this.searchText,
                userId: this.user.id,
                page: 1,
                size: 999
                page: page,
                size: pageSize,
                community,
                town
            }
            var func
            if(this.active === 0){
                func = medicineAbinetApi.getOutOfStockDeviceListByUserId
            } else {
                func = medicineAbinetApi.getDeviceListWithUserId
            }
            medicineAbinetApi.getDeviceListWithUserId(p)
            console.log('params', p)
            func(p)
                .then(res=>{
                    this.$toast.clear()
                    console.log('getDeviceListWithUserId', res)
                    console.log('getOutOfStockDeviceList', res)
                    if(res.status == 200){
                        this.list = res.detailModelList
                        var list = res.detailModelList
                        this.list = page==1? list : this.list.concat(list)
                        this.$refs.customList.endLoad(res.totalPage<=page || this.active === 0, this.list.length)
                    } else {
                        this.list = []
                        this.$refs.customList.endLoad(false, true)
                    }
                }).catch(err=>{
                    console.error(err)
                    this.list = []
                    this.$refs.customList.endLoad(false, true)
                })
        },
        accessKzl(item){
            return item.kongzhilv? Number((item.kongzhilv*100).toFixed(2)) : 0
        },
        onSearch(){
            this.list = []
            this.$refs.customList.refresh(true)
        },
        onSubmit(data){
            this.selcommunity = data.selcommunity
            this.onSearch()
        }
    },
    
}
</script>
<style scoped lang='scss'>
<style lang='scss' scoped>
.deviceIndex{
    .mr2em{
        margin-right: 2em;
    ::v-deep .custom-list .search{
        top: 50px;
    }
    .list{
        .item{
            margin-bottom: 10px;
            border-radius: 5px;
            &:last-child{
                margin-bottom: 0;
            }
            .van-icon{
                position: absolute;
                top: 50%;
                transform: translateY(calc(-50% - 15px));
                right: 0;
                color: #ccc;
            }
        }
    }   
    .bot-banner{
        position: fixed;
        bottom: 0;
        left: 0;
        width: 100%;
        box-shadow: 0 0 5px #ccc;
    }
    .delete-button{
        height: 100%;
    ::v-deep .van-list__placeholder{
        height: 60px;
    }
}
</style>
<style lang="scss">
.mainNobotHasTop{
    .deviceIndex{
        .custom-list {
            height: calc(100vh - 96px);
            .search{
                top: 96px;
            }
        }
    }
}
</style>

+ 79 - 0
mini-pro-web/src/views/device/infoLog/TimePicker.vue

@ -0,0 +1,79 @@
<template>
    <div class='infoLog-filter-panel flex f_y_c p10 c-f14 c-border-b'>
        <div style='flex:1' class='flex f_y_c'>
            <div class='bgc-fff c-border lh44 h44 cbr date-box' :class="{'c-999': !startDate}" @click="show1=true">{{!startDate? '请选择' : $moment(startDate).format('YYYY-MM-DD')}}</div>
            <div class='mlr15 c-333'>至</div>
            <div class='bgc-fff c-border lh44 h44 cbr date-box' :class="{'c-999': !endDate}" @click="show2=true">{{!endDate? '请选择' : $moment(endDate).format('YYYY-MM-DD')}}</div>
        </div>
        <van-button class='c-border-r-5 w80' type="info" @click="onSearch">搜索</van-button>
        <van-overlay :show="show1||show2" @click="show1=false,show2 = false" >
            <van-datetime-picker
                class='c-position-a'
                style='bottom:0;width:100%'
                v-show='show1'
                v-model="startDate"
                type="date"
                :min-date="minDate"
                :max-date="maxDate"
            />
            <van-datetime-picker
                class='c-position-a'
                style='bottom:0;width:100%'
                v-show='show2'
                v-model="endDate"
                type="date"
                :min-date="minDate"
                :max-date="maxDate"
            />
        </van-overlay>
    </div>
</template>
<script>
export default{
    data(){
        return {
            show1: false,
            show2: false,
            minDate: this.$moment('2021-01-01').toDate(),
            maxDate: new Date(),
            startDate: '',
            endDate: ''
        }
    },
    methods:{
        onSearch(){
            var { startDate,endDate } = this
            this.$emit('onSearch', {
                startDate,
                endDate
            })
        },
    },
}
</script>
<style scoped lang='scss'>
.infoLog-filter-panel{
    position: fixed;
    top: 50px;
    left: 0;
    width: 100%;
    background: #fff;
    z-index: 2;
    .cbr{
        border-radius: 22px;
    }
    .date-box{
        width: 100px;
        text-align: center;
    }
}
</style>
<style lang="scss">
.mainNobotHasTop{
    .infoLog-filter-panel{
        top: 96px;
    }
}
</style>

+ 93 - 58
mini-pro-web/src/views/device/infoLog/deviceLog.vue

@ -1,84 +1,119 @@
<template>
    <div class='deviceLog'>
        <div class='flex f_y_c p10 c-f14 c-border-b'>
            <div style='flex:1' class='flex f_y_c'>
                <div class='bgc-fff c-border lh44 h44 plr15 cbr' @click="show1=true">{{$moment(beginDate).format('YYYY-MM-DD')}}</div>
                <div class='mlr15 c-333'>至</div>
                <div class='bgc-fff c-border lh44 h44 plr15 cbr' @click="show2=true">{{$moment(endDate).format('YYYY-MM-DD')}}</div>
            </div>
            <van-button class='c-border-r-5 w80' type="info" @click="onSearch">搜索</van-button>
        </div>
        <!-- <CustomList 
        <TimePicker @onSearch="onSearch"/>
        <CustomList 
			ref="customList"
            :searchfun='false'
			@onLoad="onLoad"> -->
            <div v-for='(item, index) in list'>
                <div class='c-border-b bgc-fff p10 c-333 c-f14 flex f_y_c'>
                    <div style='flex: 1' class='flex f_y_c f_x_s mr30'>
                        <div>{{item.content}}</div>
                        <div>{{item.title}}</div>
                    </div>
                    <div>{{item.time}}</div>
                </div>
            :searchfun="false"
			@onLoad="onLoad">
			<div class="list plr15 mt10">
                <van-collapse v-model="activeNames">
                    <van-collapse-item 
                        v-for='(item) in list' :key="item.id"
                        :title="item.orderNum+'('+ item.name +')'" :name="item.id" :value="item.shippingTime">
                            <div v-for='(citem) in item.shipmentLogs' :key="citem.id" class='item bgc-fff plr10 c-333 c-f14  '>
                                <div class=''>
                                    <div>药品名称:{{citem.drugName}}</div>
                                    <div>出货状态:<span>{{citem.status==1? '未出货' : citem.status==2? '已出货' : citem.status==3? '出货故障' : ""}}</span></div>
                                    <div>货道信息:{{citem.layerNo}}层 {{citem.wayerNo}}道</div>
                                    <div>出货时间:{{citem.outTime}}</div>
                                    <div>出货日志详情:{{citem.description}}</div>
                                    <div>出货图片:<span v-if="!citem.pic">无出货照片</span>
                                        <van-image
                                            v-else
                                            width="100"
                                            height="100"
                                            :src="setImgUrl(citem.pic)"/>
                                    </div>
                                </div>
                            </div>
                        </van-collapse-item>
                </van-collapse>
                
            </div>
        <!-- </CustomList> -->
        <van-overlay :show="show1||show2" @click="show1=false,show2 = false" >
            <van-datetime-picker
                class='c-position-a'
                style='bottom:0;width:100%'
                v-show='show1'
                v-model="beginDate"
                type="date"
                title="选择开始日期"
                :min-date="minDate"
                :max-date="maxDate"
            />
            <van-datetime-picker
                class='c-position-a'
                style='bottom:0;width:100%'
                v-show='show2'
                v-model="endDate"
                type="date"
                title="选择截止日期"
                :min-date="minDate"
                :max-date="maxDate"
            />
        </van-overlay>
		</CustomList>
    </div>
</template>
<script>
import TimePicker from './TimePicker'
import medicineAbinetApi from '@/api/api-medicineAbinet'
export default{
    name: 'deviceLog',
    components: {
        TimePicker
    },
    props: ['deviceId', 'equNum'],
    data(){
        return {
            beginDate: new Date(),
            endDate: new Date(),
            minDate: this.$moment().add(-1,'years').toDate(),
            maxDate: new Date(),
            currentDate: '',
            list: [],
            show1: false,
            show2: false,
            startDate: '',
            endDate: '',
            activeNames: []
        }
    },
    methods:{
        onSearch(){
        onLoad({page, pageSize, searchText}){
            var { startDate, endDate } = this
            var p = {
                deviceId: this.deviceId,
                // idDevice: '',
                // lowT: this.min,
                // heightT: this.max,
				// equType: searchForm.equType,
                // networkStatus: searchForm.networkStatusName,
				// content: searchForm.deviceSearch,
                // community: len? this.community[len-1] : '',
				startTime: startDate? this.$moment(startDate).format('YYYY-MM-DD 00:00:00') : '',
				endTime: endDate? this.$moment(endDate).format('YYYY-MM-DD 23:59:59') : '',
                page: page,
                size: 30
            }
            console.log('getDeviceOrderInfoPage', p)
            medicineAbinetApi
                .getDeviceOrderInfoPage(p)
                .then(res=>{
                    console.log('getDeviceOrderInfoPage', res)
                    if(res.status == 200){
                        var list = res.detailModelList || []
                        this.list = page==1? list : this.list.concat(list)
                        this.$refs.customList.endLoad(list.length===0 || res.totalPage<=page, this.list.length)
                    } else {
                        this.onLoadError()
                    }
                }).catch(err=>{
                    console.error(err)
                    this.onLoadError()
                })
        },
        onSearch(data){
            if(data){
                this.startDate = data.startDate
                this.endDate = data.endDate
            }
            this.$refs.customList.refresh(true)
        },
        onLoadError(){
            this.$refs.customList.endLoad(false, true)
        },
        onLoad({}){
            
        }
    },
    onLoad(){
        this.list = [{content:'改变设备销售状态',title:'设备补货',time:'2020/09/01 10:03:00'},{content:'改变设备销售状态',title:'设备补货',time:'2020/09/01 10:03:00'}]
    }
}
</script>
<style scoped lang='scss'>
.deviceLog{
    .cbr{
        border-radius: 22px;
    .item{
        border-bottom: 1px solid #e1e1e1;
        padding: 10px 0;
        .van-image{
            vertical-align: text-top;
        }
        &:last-child{
            padding-bottom: 0;
            border-bottom: 0;
        }
        &:first-child{
            padding-top: 0;
        }
    }
}
</style>

+ 68 - 71
mini-pro-web/src/views/device/infoLog/faultInfo.vue

@ -1,91 +1,88 @@
<template>
    <div class='faultInfo'>
        <div class='p15 c-f14 bgc-fff c-333 grid-2 c-border-b'>
            <van-field
                v-model="f_event"
                readonly
                class='c-border'
                placeholder="请选择"
                @click="show1 = true">
                <template #right-icon>
                    <van-icon name="arrow-down" />
                </template>
            </van-field>
            <van-cell class='c-border' @click="show2 = true">
                <template #default>
                    <div class='c-t-center'>{{$moment(currenDate).format('YYYY-MM-DD')}}</div>
                </template>
            </van-cell>
        </div>
        <div v-for='(item, index) in list'>
            <div class='flex c-border-b c-333 c-f14 p10 bgc-fff f_y_c f_x_s'>
                <div style='flex:1;width:0' class='text-overhidd mr20'>{{item.content}}</div>
                <div>{{item.time}}</div>
        <TimePicker @onSearch="onSearch"/>
        <CustomList 
			ref="customList"
            :searchfun="false"
			@onLoad="onLoad">
			<div class="list plr15 mt10">
                <div v-for='(item, index) in list' :key="item.id" >
                    <div class=' c-border-b c-333 c-f14 p10 bgc-fff f_y_c f_x_s'>
                        <div  class='mr20'>{{item.type}}:{{item.remark}}</div>
                        <div class="pt5">{{item.logTime}}</div>
                    </div>
                </div>
            </div>
        </div>
        <van-overlay :show="show1||show2" @click="show1=false,show2 = false" >
            <van-picker
                class='c-position-a'
                style='bottom:0;width:100%'
                v-show='show1'
                show-toolbar
                :columns="eventList"
                value-key='dictValue'
                @confirm="onConfirm"
                @cancel="show1=false"
            />
            <van-datetime-picker
                class='c-position-a'
                style='bottom:0;width:100%'
                v-show='show2'
                v-model="endDate"
                type="date"
                :min-date="minDate"
                :max-date="maxDate"
            />
        </van-overlay>
		</CustomList>
    </div>
</template>
<script>
import TimePicker from './TimePicker'
import medicineAbinetApi from '@/api/api-medicineAbinet'
export default{
    name: 'faultInfo',
    components: {
        TimePicker
    },
    props: ['deviceId', 'equNum'],
    data(){
        return {
            f_event: '',
            eventList: [],
            show1: false,
            show2: false,
            currenDate: new Date(),
            minDate: this.$moment().add(-1,'years').toDate(),
            maxDate: new Date(),
            list: [{content:'货道电机超时',time:'10:03:00'}]
            list: [],
            startDate: '',
            endDate: ''
        }
    },
    mounted(){
        this.onSearch()
    },
    methods:{
        onConfirm(obj, index){
        onLoad({page, pageSize, searchText}){
            var { startDate, endDate } = this
            var p = {
                idDevice: this.equNum,
				// equClass: searchForm.equType,
                // networkStatus: searchForm.networkStatusName || '',
				// content: searchForm.deviceSearch,
                // community: len? this.community[len-1] : '',
				startTime: startDate? this.$moment(startDate).format('YYYY-MM-DD 00:00:00') : '',
				endTime: endDate? this.$moment(endDate).format('YYYY-MM-DD 23:59:59') : '',
                page: page,
                size: 30
            }
            console.log('params', p)
            medicineAbinetApi
                .warrayGetFault(p)
                .then(res=>{
                    console.log('warrayGetFault', res)
                    if(res.status == 200){
                        this.totalCount = res.totalCount
                        var list = res.detailModelList
                        this.list = page==1? list : this.list.concat(list)
                        this.$refs.customList.endLoad(res.totalPage<=page, this.list.length)
                    } else {
                        this.onLoadError()
                    }
                }).catch(err=>{
                    console.error(err)
                    this.onLoadError()
                })
        },
        onSearch(data){
            if(data){
                this.startDate = data.startDate
                this.endDate = data.endDate
            }
            this.$refs.customList.refresh(true)
        },
        onLoadError(){
            this.$refs.customList.endLoad(false, true)
        },
        initMain(){
        }
    },
    created(){
        this.eventList = [{dictValue:'全部事件',dictCode:'all'}]
    }
    
}
</script>
<style scoped lang='scss'>
.faultInfo{
    .grid-2{
        display: grid;
        grid-template-columns: 1fr 1fr;
        grid-column-gap: 20px;
    }
    .text-overhidd{
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        word-break: break-all;
    }
 
}
</style>
</style>

+ 31 - 11
mini-pro-web/src/views/device/infoLog/index.vue

@ -1,13 +1,15 @@
<template>
    <div class='device-infoLog-index'>
        <van-tabs v-model="active">
            <van-tab title="设备日志"></van-tab>
            <van-tab title="故障信息"></van-tab>
            <van-tab title="离线日志"></van-tab>
        </van-tabs>
        <device-log v-show='active==0'></device-log>
        <fault-info v-show='active==1'></fault-info>
        <offline-log v-show='active==2'></offline-log>
        <van-sticky :offset-top="offsetTop">
            <van-tabs v-model="active">
                <van-tab title="出货日志"></van-tab>
                <van-tab title="故障日志"></van-tab>
                <van-tab title="离线日志"></van-tab>
            </van-tabs>
        </van-sticky>
        <device-log v-show='active==0' :deviceId="deviceId" :equNum="equNum"></device-log>
        <fault-info v-show='active==1' :deviceId="deviceId" :equNum="equNum"></fault-info>
        <offline-log v-show='active==2' :deviceId="deviceId" :equNum="equNum"></offline-log>
    </div>
</template>
<script>
@ -24,6 +26,8 @@ export default{
    data(){
        return {
            active: 0,
            deviceId: this.$route.query.deviceId,
            equNum: this.$route.query.equNum,
        }
    },
    methods:{
@ -34,8 +38,24 @@ export default{
    }
}
</script>
<style scoped lang='scss'>
<style lang='scss'>
.device-infoLog-index{
    .van-overlay{
        z-index: 999;
    }
    .custom-list{
        height: calc(100vh - 50px);
        padding-top: 66px;
    }
}
.mainNobotHasTop{
    .device-infoLog-index{
        .custom-list {
            height: calc(100vh - 96px);
            .search{
                top: 96px;
            }
        }
    }
}
</style>
</style>

+ 62 - 51
mini-pro-web/src/views/device/infoLog/offlineLog.vue

@ -1,74 +1,85 @@
<template>
    <div class='offlineLog'>
        <div class='flex f_y_c p10 c-f14 c-border-b'>
            <div style='flex:1' class='flex f_y_c'>
                <div class='bgc-fff c-border lh44 h44 plr15 cbr' @click="show1=true">{{$moment(beginDate).format('YYYY-MM-DD')}}</div>
                <div class='mlr15 c-333'>至</div>
                <div class='bgc-fff c-border lh44 h44 plr15 cbr' @click="show2=true">{{$moment(endDate).format('YYYY-MM-DD')}}</div>
            </div>
            <van-button class='c-border-r-5 w80' type="info" @click="onSearch">搜索</van-button>
        </div>
        <div v-for='(item, index) in list'>
            <div class='c-border-b bgc-fff p10 c-333 c-f14 flex f_y_c'>
                <div style='flex: 1;width:0;' class='mr20'>
                    <div>{{item.time}}</div>
        <TimePicker @onSearch="onSearch"/>
        <CustomList 
			ref="customList"
            :searchfun="false"
			@onLoad="onLoad">
			<div class="list plr15 mt10">
                <div v-for='(item, index) in list' :key="item.id">
                    <div class='c-border-b bgc-fff p10 c-333 c-f14 flex f_y_c'>
                        <div style='flex: 1;width:0;' class='mr20'>
                            <div>{{item.logTime}}</div>
                        </div>
                        <div>{{item.type}}</div>
                    </div>
                </div>
                <div>{{item.online}}</div>
            </div>
        </div>
        <van-overlay :show="show1||show2" @click="show1=false,show2 = false" >
            <van-datetime-picker
                class='c-position-a'
                style='bottom:0;width:100%'
                v-show='show1'
                v-model="beginDate"
                type="date"
                title="选择开始日期"
                :min-date="minDate"
                :max-date="maxDate"
            />
            <van-datetime-picker
                class='c-position-a'
                style='bottom:0;width:100%'
                v-show='show2'
                v-model="endDate"
                type="date"
                title="选择截止日期"
                :min-date="minDate"
                :max-date="maxDate"
            />
        </van-overlay>
		</CustomList>
    </div>
</template>
<script>
import TimePicker from './TimePicker'
import medicineAbinetApi from '@/api/api-medicineAbinet'
export default{
    name: 'offlineLog',
    components: {
        TimePicker
    },
    props: ['deviceId', 'equNum'],
    data(){
        return {
            beginDate: new Date(),
            endDate: new Date(),
            minDate: this.$moment().add(-1,'years').toDate(),
            maxDate: new Date(),
            currentDate: '',
            list: [],
            show1: false,
            show2: false,
            startDate: '',
            endDate: ''
        }
    },
    mounted(){
        this.onSearch()
    },
    methods:{
        onSearch(){
        onLoad({page, pageSize, searchText}){
            var { startDate, endDate } = this
            var p = {
                idDevice: this.equNum,
                // networkStatus: searchForm.networkStatusName,
				startTime: startDate? this.$moment(startDate).format('YYYY-MM-DD 00:00:00') : '',
				endTime: endDate? this.$moment(endDate).format('YYYY-MM-DD 23:59:59') : '',
                page: page,
                size: 30
            }
            console.log('warrayGetOffline', p)
            medicineAbinetApi
                .warrayGetOffline(p)
                .then(res=>{
                    console.log('warrayGetOffline', res)
                    if(res.status == 200){
                        var list = res.detailModelList || []
                        this.list = page==1? list : this.list.concat(list)
                        this.$refs.customList.endLoad(list.length===0 || res.totalPage<=page, this.list.length)
                    } else {
                        this.onLoadError()
                    }
                }).catch(err=>{
                    console.error(err)
                    this.onLoadError()
                })
        },
        onSearch(data){
            if(data){
                this.startDate = data.startDate
                this.endDate = data.endDate
            }
            this.$refs.customList.refresh(true)
        },
        onLoadError(){
            this.$refs.customList.endLoad(false, true)
        },
    },
    created(){
        this.list = [{online:'离线',time:'2020/09/01 10:03:00'},{online:'离线',time:'2020/09/01 10:03:00'}]
    }
}
</script>
<style scoped lang='scss'>
.offlineLog{
    .cbr{
        border-radius: 22px;
    }
    
}
</style>

+ 3 - 1
mini-pro-web/src/views/device/sell.vue

@ -1,7 +1,7 @@
<template>
    <div class='deviceSell'>
        <div class='plr15 ptb20 c-333 c-f14 bgc-fff c-border-b flex f_y_c f_x_s'>
            <div>当前售货状态:<span>{{status? '在售' : '停售'}}</span></div>
            <div>当前售货状态:<span>{{status? '设备上架' : '设备维护'}}</span></div>
            <van-switch @change="switchSell" inactive-color='#ccc' active-color='#17b3ec' v-model="status" />
        </div>
    </div>
@ -33,6 +33,8 @@ export default{
				medicineAbinetApi
					.updateSaleStatus(p)
					.then(res => {
                        this.$emitRefreshPage('deviceDetail')
                        this.$emitRefreshPage('deviceIndex')
                        this.$toast('操作成功')
					})
					.catch(err=>{

+ 30 - 0
mini-pro-web/src/views/device/stock.vue

@ -0,0 +1,30 @@
<template>
<div class="device-stock">
    <DeviceDetail :isView="true"/>
</div>
</template>
<script>
import DeviceDetail from '@/views/replenishment/start/deviceDetail'
export default {
    name: "deviceStock",
    components: {
        DeviceDetail
    },
    data() {
        return {
            deviceId: this.$route.query.id,
        };
    },
    created() {
        
    },
    methods: {
        
    },
};
</script>
<style scoped lang='scss'>
.device-stock {
    
}
</style>

+ 21 - 18
mini-pro-web/src/views/device/temperature/index.vue

@ -5,7 +5,7 @@
                <span>设备实时温湿度</span>
                <van-button size="small" type="text" class='tbtn w60 bgc-fff c-17B3EC' @click='initMain'>获取</van-button>
            </div>
            <div class='c-f20'>{{form.temperature}}°<span class='ml20'>{{form.humidity}}%</span></div>
            <div class='c-f20'>{{temperature}}°<span class='ml20'>{{humidity}}%</span></div>
            <div class='mt10'>设备实时温度每10分钟会从设备端返回一次</div>
        </div>
        <div class='mt10 p10 bgc-fff c-f14 c-333 c-border-tb'>
@ -17,21 +17,21 @@
        </div>
        <div v-if='form.temperaturecontrol'>
            <div class='c-333 c-f14 bgc-fff p15 c-border-b' >
                <div class='flex f_y_c'>
                <!-- <div class='flex f_y_c'>
                    <span>加热控制:</span>
                    <van-radio-group class='ml20' v-model="form.heat" direction="horizontal">
                        <van-radio name="0">关闭</van-radio>
                        <van-radio name="1">开启</van-radio>
                    </van-radio-group>
                </div>
                <div class='flex mt20'>
                </div> -->
                <div class='flex '>
                    <div class='lh46'>请设置目标温度值:</div>
                    <div style='flex:1' class='ml10'>
                        <div class='flex f_y_c'><van-field class='c-border w80' v-model="form.temperature" maxlength='2' type="digit" /><span class='ml10'>度</span></div>
                        <!-- <van-notice-bar class='bgc-fff pl0' wrapable :scrollable="false" >可输入的值范围为: {{form.heat==0?'2-25°':form.heat==1?'20-40°':''}}</van-notice-bar> -->
                    </div>
                </div>
                <div class='mt10'>最后一次发送的温度值为 22°</div>
                <!-- <div class='mt10'>最后一次发送的温度值为 22°</div> -->
                <div class='mt10 c-999'>指令发送成功后,请等待设备生效,设备每隔十分钟左右会返回一次最新实时温度值</div>
            </div>
            <div class='mt10 p10 bgc-fff c-f14 c-333 c-border-tb' v-if='form.temperaturecontrol'>
@ -69,7 +69,7 @@
                    <van-slider button-size='30px' v-model="form.humidity" @change="onChange" />
                    <div class='ml15'>{{form.humidity}}%</div>
                </div>
                <div class='mt20'>最后一次发送的湿度调整值为%</div>
                <!-- <div class='mt20'>最后一次发送的湿度调整值为%</div> -->
                <div class='mt10 c-999'>指令发送成功后,请等待设备生效,设备每隔十分钟左右会返回一次最新实时湿度值</div>
            </div>
            <div class='mt10 p10 bgc-fff c-f14 c-333 c-border-tb' v-if='form.humiditycontrol'>
@ -78,7 +78,7 @@
                    <van-switch inactive-color='#ccc' active-color='#17b3ec' v-model="checked2" />
                </div>
            </div>
            <div v-if='checked2'>
            <div v-if='checked2&&form.humiditycontrol'>
                <div class='flex c-333 c-f14 bgc-fff p15'>
                    <div class='lh46'>当湿度高于:</div>
                    <div style='flex:1' class='ml10'>
@ -102,6 +102,8 @@ export default{
    name: 'temperatureIndex',
    data(){
        return {
            temperature: '',
            humidity: '',
            checked1: '',
            checked2: '',
            form:{
@ -110,7 +112,7 @@ export default{
                temperature: '',
                humiditycontrol: '',
                temperaturecontrol:'',
                heat: '',
                heat: 1,
                warningTemperatureHeight: '',
                waringHumidityHeight: '',
                warningTemperatureLow: '',
@ -137,13 +139,17 @@ export default{
            if(n==0){
                this.form.checked1 = false;
                this.form.temperature = '';
                this.heat = ''
                this.form.heat = 1
            } else {
                this.form.temperature = this.temperature;
            }
        },
        humidityChange(n){
            if(n==0){
                this.form.checked2 = false;
                this.form.humidity = '';
            } else {
                this.form.humidity = this.humidity
            }
        },
        save(){
@ -169,8 +175,6 @@ export default{
                this.$toast('请设置温度预警值')
                return
            }
            if(!this.form.humiditycontrol){
                this.$toast('请开启湿度控制')
                return
@ -179,7 +183,6 @@ export default{
                this.$toast('请设置目标湿度值')
                return
            }
            if(!this.checked2){
                this.$toast('请开启湿度预警')
                return
@ -189,14 +192,11 @@ export default{
                return
            }
            let json = {}
            Object.assign(json, JSON.parse(JSON.stringify(this.form)));
            json.humiditycontrol = json.humiditycontrol?'1':'0';
            json.temperaturecontrol = json.temperaturecontrol?'1':'0'
            json.heat = !json.heat&&json.heat!=0?'0':this.form.heat
            json.heat = 1
            medicineAbinetApi.updateTAndH(json).then(res=>{
                this.$toast.clear()
                if(res.status==200){
@ -215,12 +215,15 @@ export default{
            medicineAbinetApi.findDeviceById({deviceId: this.$route.query.id}).then(res=>{
                this.$toast.clear()
                if(res.status==200){
                    console.log(res);
                    console.log('findDeviceById', res);
                    this.temperature = res.obj.device.nowTemperature;
                    this.humidity = res.obj.device.nowHumidity;
                    this.form.humidity = res.obj.device.humidity;
                    this.form.humiditycontrol = res.obj.device.humiditycontrol&&res.obj.device.humiditycontrol==1?true:false;
                    this.form.temperature = res.obj.device.temperature;
                    this.form.temperaturecontrol = res.obj.device.temperaturecontrol&&res.obj.device.temperaturecontrol==1?true:false;
                    this.form.heat = res.obj.device.heat;
                    this.form.heat = 1; //res.obj.device.heat;
                    this.checked1 = res.obj.device.warningTemperatureHeight!==null||res.obj.device.warningTemperatureLow!==null;
                    this.checked2 = res.obj.device.waringHumidityHeight!==null||res.obj.device.waringHumidityLow!==null;
                    this.form.waringHumidityHeight = res.obj.device.waringHumidityHeight;

+ 20 - 11
mini-pro-web/src/views/drug/list.vue

@ -21,20 +21,20 @@
                class="item mb10 bgc-fff btb-e1e1e1 pt10 pb10 plr15">
                <van-row class="lh25 c-333">
                    <span class="fs-17">{{item.drugName}}</span>
                    <span class="fs-14 ml20">处方名称/项目名称:{{item.drugName}}</span>
                    <span class="fs-14 ml20">药品编码:{{item.drugCode}}</span>
                </van-row>
                <van-row class="lh25">
                    <van-col span="12" class="c-999">规格:<span class="c-333">{{item.specif}}</span></van-col>
                    <van-col span="12" class="c-999">零售价:<span class="c-333">{{item.price}}</span></van-col>
                    <van-col span="12" class="c-999">分类:<span class="c-333">{{item.drugClass}}</span></van-col>
                </van-row>
                <van-row class="lh25">
                    <van-col span="12" class="c-999">医保支付价:<span class="c-333"></span></van-col>
                    <van-col span="12" class="c-999">医保支付比例:<span class="c-333"></span></van-col>
                    <van-col span="24" class="c-999">剂型:<span class="c-333">{{item.dosForm}}</span></van-col>
                    <!-- <van-col span="12" class="c-999">医保支付比例:<span class="c-333"></span></van-col> -->
                </van-row>
                <van-row class="lh25">
                <!-- <van-row class="lh25">
                    <van-col span="12" class="c-999">基药:<span class="c-333"></span></van-col>
                    <van-col span="12" class="c-999">药品类别:<span class="c-333"></span></van-col>
                </van-row>
                </van-row> -->
                <!-- <div class="c-ff5e6c fs-14 lh25">高危药品:</div> -->
            </div>
        </div>
@ -46,8 +46,10 @@
        <SetStockDialog 
            v-model="setStockShow" 
            :trackId="trackId"
            :bussiness="5"
            :drugId="drugId"/>
            :bussiness="bussiness"
            :drugId="drug.id"
            @onConfirm="onConfirm"/>
            
    </div>
</template>
@ -71,10 +73,12 @@ export default {
            value: "",
            list: [],
            setStockShow: false,
            drugId: ''
            bussiness: this.$route.query.bussiness || '',
            drug: ''
        }
    },
    async created(){
        this.bussiness = this.trackId? 5 : this.bussiness
        this.getDrugDictionary()
    },
    methods: {
@ -106,14 +110,19 @@ export default {
            this.$router.back()
        },
        addDrug(item){
            if(this.trackId){
                this.drugId = item.id
            if(this.trackId || this.bussiness==6){
                this.drug = item
                this.setStockShow = true
                return
            }
            this.$EventBus.$emit('drug-sel', item)
            this.$router.back()
        },
        onConfirm(stock){
            this.drug.upInventory = stock
            this.$EventBus.$emit('drug-sel', this.drug)
            this.$router.back()
        }
    }
};
</script>

+ 505 - 139
mini-pro-web/src/views/index/Index.vue

@ -1,174 +1,540 @@
<template>
	<div class="index-wrap pt30">
    	<!-- <div class="panel plr15">
	<div class="index-wrap">
        <!-- <div class="home-text">首页</div> -->
        <div class="mask" v-show="drowMenuShow"></div>
        <div class="select" >
            <div class="drop-menu" :class="{active: drowMenuShow}">
                <div class="drop-menu-title tc fs-14" @click="drowMenuShow=!drowMenuShow">
                    <span class="v-middle">{{selcommunityName}}</span>
                    <van-icon name="arrow-down" />
                </div>
                <div class="drop-menu-area kitbox">
                    <div class="drop-menu-area-left" v-if="townList&&townList.length">
                        <van-sidebar v-model="activeKey">
                            <van-sidebar-item v-for="(item, i) in townList" :key="i" :title="item.townName" />
                        </van-sidebar>
                    </div>
                    <div class="drop-menu-area-right fs-14">
                        <div v-for="(item, i) in communityList" :key="i" @click="onSelect(item)">{{item.hospitalName}}</div>
                    </div>
                </div>
            </div>
        </div>
        <!-- 设备概况 -->
        <div class="panel mt10 sbzl">
            <div class="kitbox pt15 plr15 box-flex-c">
                <div class="box-flex-c c-333 fs-16 f-bold">设备概况</div>
                <div class="box-flex-c c-333 f-bold fs-12">在线率:{{ overview.onlineRate }}</div>
            </div>
            <div class="box-flex-c pt10 pb20 plr15">
                <div class="Online" @click="gotoDeviceList(1)">
                    <div class="equipment-num">{{ overview.onlineTotal }}</div>
                    <div class="equipment-text">在线设备</div>
                </div>
                <div class="total" @click="gotoDeviceList()">
                    <div class="equipment-num">{{ overview.total }}</div>
                    <div class="equipment-text">运营总台数</div>
                </div>
                <div class="offline" @click="gotoDeviceList(0)">
                    <div class="equipment-num">{{ overview.noOnlineTotal }}</div>
                    <div class="equipment-text">离线设备</div>
                </div>
            </div>
        </div>
        <!-- 运维数据 -->
        <div class="panel plr15 mt10 cygn">
			<div class="kitbox pt15 ">
				<div class="box-flex-1 c-333 fs-16 f-bold">今日订单数量</div>
				<div class="c-666 fs-12 box-v-middle">
					<div @click="searchTypeShow=!searchTypeShow" class="drop-sel c-666 fs-12 plr10 ptb4">
						<span  class="v-middle">{{searchType}}</span>
						<van-icon class="v-middle ml4" name="arrow-down" />
						<div v-show="searchTypeShow" class="sel-body fs-12 c-666">
							<div v-for="(item, i) in options" :key="i" v-show="searchType!=item" @click.stop="searchType=item;searchTypeShow=false;search()" class="ptb6">{{item}}</div>
						</div>
					</div>
				</div>
				<div class="box-flex-1 c-333 fs-16 f-bold">运维数据</div>
			</div>
			<div class="c-20d7ad fs-23 pt10">
				752,600
			<div class="pt10">
				<div class="pb20">
                    <van-row>
                        <van-col @click="gotoDevice(0)" class="col col-tl" span="12">
                            <div class="operations-num">{{ maintain.addTotal }}</div>
                            <div class="operations-text"><span><img class="img" src="../../assets/images/waiting-equipment.png" alt=""></span>待入库设备数</div>
                        </van-col>
                        <van-col @click="gotoDevice()" class="col" span="12">
                            <div class="operations-num">{{ maintain.hcWaringTotalNum }}</div>
                            <div class="operations-text"><span><img class="img" src="../../assets/images/thermometer.png" alt=""></span>温湿度预警数</div>
                        </van-col>
                        <van-col @click="gotoDeviceList(0)" class="col col-t col-bl" span="12">
                            <div class="operations-num">{{ maintain.noOnlineTotal1WithUserId }}</div>
                            <div class="operations-text"><span><img class="img" src="../../assets/images/waiting-equipment.png" alt=""></span>离线设备数</div>
                        </van-col>
                        <van-col @click="toOrderPage()" class="col col-t" span="12">
                            <div class="operations-num">{{ maintain.noGetDrugNum }}</div>
                            <div class="operations-text"><span><img class="img" src="../../assets/images/offline-medicine.png" alt=""></span>待取药订单数</div>
                        </van-col>
                    </van-row>
                </div>
			</div>
			<div class="c-666 fs-14 pt10 pb10">今日补货量 <span class="ml10 c-17b3ec">0</span></div>
		</div> -->
		<div class="">
			<div class="panel  sbzl">
				<div class="kitbox pt15 plr15">
					<div class="box-flex-1 c-333 fs-16 f-bold">设备总览</div>
				</div>
				<div class="pt20 pb20 plr5">
					<van-row class="">
						<van-col span="6" class="tc ">
							<div class="fs-23 c-17b3ec">{{countObj.total}}</div>
							<div class="fs-14 c-666 pt5">全部设备</div>
						</van-col>
						<van-col span="6" class="tc">
							<div class="fs-23 c-ff9526">{{countObj.onlineTotal}}</div>
							<div class="fs-14 c-666 pt5">在线设备</div>
						</van-col>
						<van-col span="6" class="tc">
							<div class="fs-23 c-ff5e6c">{{(countObj.onlineRate * 100).toFixed(0)}}%</div>
							<div class="fs-14 c-666 pt5">在线率</div>
						</van-col>
						<van-col span="6" class="tc">
							<div class="fs-23 c-17b3ec">{{countObj.saleTotal}}</div>
							<div class="fs-14 c-666 pt5">在售设备</div>
						</van-col>
					</van-row>
				</div>
		</div>
        <!-- 取药次数 -->
        <div v-if="medicineShow" class="panel plr15 mt10 medicine">
			<div class="kitbox pt15 box-flex-c">
				<div class="box-flex-c c-333 fs-16 f-bold">取药次数</div>
                <div class="box-flex-c c-333 fs-12 f-bold time">
                    <ul class="ul">
                        <li @click="medicineTime('1')" class="border-r" :class="medicineBag == '1' ? 'li-bag':''">今日</li>
                        <li @click="medicineTime('7')" class="border-r" :class="medicineBag == '7' ? 'li-bag':''">7日</li>
                        <li @click="medicineTime('30')" class="border-r" :class="medicineBag == '30' ? 'li-bag':''">30日</li>
                        <li @click="medicineTime('90')" class="border-r" :class="medicineBag == '90' ? 'li-bag':''">90日</li>
                        <li @click="medicineTime('全部')" :class="medicineBag == '' ? 'li-bag':''">全部</li>
                    </ul>
                </div>
			</div>
            <div class="pt24 pb19">
                <div class="medicine-b-l">
                    <div class="medicine-b-g-num">
                        {{ shippingType.total }}
                        <span>次</span>
                    </div>
                </div>
                <div class="scan">扫码取药:{{ shippingType.saomaTotal }}次</div>
                <div class="care">医保卡取药:{{ shippingType.yibaoTotal }}次</div>
            </div>
		</div>
		<div class="mt10">
			<div class="panel cygn">
				<div class="kitbox pt15 plr15">
					<div class="box-flex-1 c-333 fs-16 f-bold">常用功能</div>
				</div>
				<div class="ptb10 plr5">
					<van-row class="">
						<van-col @click="gotoUrl('/order/list')" span="6" class="tc ">
							<div class="fs-23 c-17b3ec"><img src="@/assets/images/dingdanguanli.png" alt=""></div>
							<div class="fs-14 c-666 pt5">订单管理</div>
						</van-col>
						<van-col @click="gotoUrl('/device')" span="6" class="tc">
							<div class="fs-23 c-ff9526"><img src="@/assets/images/shebeiguanli.png" alt=""></div>
							<div class="fs-14 c-666 pt5">设备管理</div>
						</van-col>
					</van-row>
				</div>
        <!-- 电子处方单 -->
        <div class="panel plr15 mt10 medicine">
			<div class="kitbox pt15 box-flex-c">
				<div class="box-flex-c c-333 fs-16 f-bold">电子处方单</div>
                <div class="box-flex-c c-333 fs-12 f-bold time">
                    <ul class="ul">
                        <li @click="prescriptionTime('1')" class="border-r" :class="prescriptionBag == '1' ? 'li-bag':''">今日</li>
                        <li @click="prescriptionTime('7')" class="border-r" :class="prescriptionBag == '7' ? 'li-bag':''">7日</li>
                        <li @click="prescriptionTime('30')" class="border-r" :class="prescriptionBag == '30' ? 'li-bag':''">30日</li>
                        <li @click="prescriptionTime('90')" class="border-r" :class="prescriptionBag == '90' ? 'li-bag':''">90日</li>
                        <li @click="prescriptionTime('全部')" :class="prescriptionBag == '' ? 'li-bag':''">全部</li>
                    </ul>
                </div>
			</div>
            <div class="pt24 pb19">
                <div class="medicine-b-l prescription">
                    <div class="medicine-b-g-num">
                        {{ prescriptionStatics.total }}
                        <span>次</span>
                    </div>
                </div>
                <div class="prescription-num">药品数量:{{ prescriptionStatics.drugTotal }}件</div>
            </div>
		</div>
        <!-- 销售额 -->
        <div v-if="sales" class="panel plr15 mt10 medicine">
			<div class="kitbox pt15 box-flex-c">
				<div class="box-flex-c c-333 fs-16 f-bold">销售额</div>
                <div class="box-flex-c c-333 fs-12 f-bold time">
                    <ul class="ul">
                        <li @click="salesTime('1')" class="border-r" :class="salesBag == '1' ? 'li-bag':''">今日</li>
                        <li @click="salesTime('7')" class="border-r" :class="salesBag == '7' ? 'li-bag':''">7日</li>
                        <li @click="salesTime('30')" class="border-r" :class="salesBag == '30' ? 'li-bag':''">30日</li>
                        <li @click="salesTime('90')" class="border-r" :class="salesBag == '90' ? 'li-bag':''">90日</li>
                        <li @click="salesTime('全部')" :class="salesBag == '' ? 'li-bag':''">全部</li>
                    </ul>
                </div>
			</div>
            <div class="pt20 pb20 sales-data">
                <div>¥{{ amount }}</div>
                <div style="display:none;">月同比:<span>0.40%</span></div>
                <div style="display:none;">日环比:<span>5.00%</span></div>
            </div>
            <div id="sales-chart" class="sales-chart"></div>
		</div>
        <div class="home-bottom"></div>
	</div>
</template>
<script>
import { findOneUser} from "@/api/login";
import * as echarts from 'echarts';
import medicineAbinetApi from '@/api/api-medicineAbinet'
export default {
	name: "index",
	name: "homeIndex",
	components: {
		
  	},
    watch: {
        drowMenuShow(n){
            var body = document.getElementsByTagName('body')[0]
            if(n){
                body.classList.add('over-hidden')
            } else {
                body.classList.remove('over-hidden')
            }
        },
        activeKey(n){
            this.loadChildren()
        }
    },
    computed:{
        selcommunityName(){
            if(this.selcommunity){
                if(this.selcommunity.hospital === ''){
                    var item = this.townList[this.activeKey]
                    return item.town === ''? "全部" : item.townName
                } else {
                    return this.selcommunity.hospitalName
                }
            } 
            return "全部"
        }
    },
  	data() {
    	return {
			searchTypeShow: false,
            searchType: "今日",
			options: ['今日', '7天内', '30天内'],
			countObj: {
				"total": 0,							//总的在线数
				"saleTotal": 0,						//在售数
				"onlineRate": 0,					//在线率
				"onlineTotal": 0,						//在线设备数
				"outCount": 0 						//缺货设备数
			}
            medicineBag:'1',
            medicineData:false,
            medicineShow:true,
            sales:true,
            prescriptionBag:'1',
            salesBag:'1',
            count:[],
            date:[],
            amount:'- -',
			overview:{
                total:'- -', // 总台数
                noOnlineTotal:'- -', // 不在线数
                onlineRate:'- -', // 在线率
                onlineTotal:'- -', // 在线台数
            },
            maintain:{
                hcWaringTotalNum:'- -', // 温湿度异常警告
                noOnlineTotal1WithUserId:'- -', // 不在线数
                noGetDrugNum:'- -', // 待取药订单数
                addTotal:'- -', // 缺货设备数
            },
            shippingType:{
                saomaTotal:'- -',
                total:'- -',
                yibaoTotal:'- -'
            },
            prescriptionStatics:{
                total:'- -',
                drugTotal:'- -'
            },
            drowMenuShow: false,
            townList: [],
            communityList: [],
            selcommunity: '',
            activeKey: 0,
            defaultOption: [
                { townName: '全部', town: "", children: [{hospital: '', hospitalName: '全部'}] },
            ],
            first: false
    	}
  	},
	created(){
		this.countall()
	},
        this.first = true
		this.refreshData()
        this.getOrgList()
        console.log('this.$store.user.state',this.$store.state.user.curRoleCode)
        if(this.$store.state.user.curRoleCode =='replenisher'){
            this.medicineShow = false;
            this.sales = false;
        }
    },
    activated(){
        if(this.first){
            this.first = false
        } else {
            this.refreshData()
        }
    },
    mounted(){
        this.echartsData();
    },
  	methods: {
        // 设备概况 运营数据
		countall(){
            var p = this.getTownParams()
			medicineAbinetApi
				.countAllDevice({
					userId: this.user.id
				.countAllDevice(p)
				.then(res=>{
                    // console.log('countall', res);
                    this.overview = res.obj.overview;
                    this.maintain = res.obj.maintain;
				})
				.catch(err=>{
					console.error(err)
				})
        },
        //跳转
        gotoDevice(active){
            var p = this.getTownUrlParams()
            p.active = active
            this.$router.push({
                path: '/device/index',
                query: p
            })
        },
        // 取药次数
        medicine(){
            var p = this.getTownParams()
            p.day = this.medicineBag
            console.log('medicine', p)
            medicineAbinetApi
				.getmedicine(p)
				.then(res=>{
                    console.log('medicine', res)
                    this.medicineData = true;
                    this.shippingType = res.obj;
				})
				.catch(err=>{
                    console.error(err)
                    this.medicineData = true;
				})
        },
        // 电子处方单
        prescriptions(){
            var p = this.getTownParams()
            p.day = this.prescriptionBag
            medicineAbinetApi
				.getprescriptions(p)
				.then(res=>{
					console.log('countall', res)
					this.countObj = _.assign(this.countObj, res.obj) 
                    // console.log('prescriptions', res)
                    this.prescriptionStatics = res.obj;
				})
				.catch(err=>{
					console.error(err)
				})
		}
        },
        // 取药时间查询
        medicineTime(val){
            if(this.medicineData){
                if(val == '全部'){
                    this.medicineBag = '';
                    console.log('全部')
                }else{
                    this.medicineBag = val;
                    console.log('1,3,7,9')
                }
                this.medicineData = false;
                this.medicine();
                
            }
        },
        // 电子处方单查询
        prescriptionTime(val){
            if(val == '全部'){
                this.prescriptionBag = '';
                this.prescriptions();
                console.log('全部')
            }else{
                this.prescriptionBag = val;
                this.prescriptions();
                console.log('1,3,7,9')
            }
        },
        // 销售额查询
        salesTime(val){
            if(val == '全部'){
                this.salesBag = '';
                console.log('全部')
            }else{
                this.salesBag = val;
                console.log('1,3,7,9')
            }
            this.echartsData();
        },
        echartsData(){
            if(this.sales){
                var p = this.getTownParams()
                p.day = this.salesBag
                medicineAbinetApi
                    .getechartsData(p)
                    .then(res=>{
                        // console.log('echartsData', res);
                        this.amount = res.obj.amount;
                        this.count = res.obj.amountdateList.map((item) =>{
                            return item.count
                        });
                        this.date = res.obj.amountdateList.map((item) =>{
                            return item.date
                        });
                        // 基于准备好的dom,初始化echarts实例
                        var myChart;
                        if (myChart != null && myChart != "" && myChart != undefined){
                            // chartDom.clear();
                            myChart.dispose();
                            // document.getElementById('sales-chart').innerHTML = '';
                        }
                        var chartDom = document.getElementById('sales-chart');
                        myChart = echarts.init(chartDom);
                        var option;
                        option = {
                            grid:{
                                left: '3%',
                                right: '4%',
                                bottom: '2%',
                                top:'5%',
                                containLabel: true
                            },
                            tooltip: {
                                trigger: 'axis'
                            },
                            xAxis: {
                                type: 'category',
                                boundaryGap: false,
                                data: this.date,
                                axisTick:{
                                    show:false, // X轴刻度隐藏
                                },
                                axisLabel:{
                                    fontSize:'8', // X轴文字字体大小
                                }
                            },
                            yAxis: {
                                type: 'value'
                            },
                            series: [
                                {
                                data: this.count,
                                type: 'line'
                                }
                            ]
                        };
                        // if (myChart != null && myChart != "" && myChart != undefined) {
                        //     myChart.dispose();
                        // }
                        option && myChart.setOption(option);
                    })
                    .catch(err=>{
                        console.error(err)
                    })
            }
        },
        refreshData(){
            this.countall();
            this.medicine();
            this.prescriptions();
        },
        getTownParams(){
            var p = {
                userId: this.user.id,
            }
            if(this.selcommunity){
                if(this.selcommunity.hospital===''){
                    var item = this.townList[this.activeKey]
                    if(item.town === ''){
                        p.level = ''; 
                        p.area = '';
                    } else {
                        p.level = 2; 
                        p.area = item.town;
                    }
                } else {
                    p.level = 3; //(name = "level", value = "1、市级、2、区级、3、社区", required = false)
                    p.area = this.selcommunity.hospital
                }
            }
            return p
        },
        getOrgList(){
            findOneUser({
                id: this.user.id
            }).then(async res => {
                // "saasAdmin": "管理员"; regionAdmin" "区域管理员" ; communityAdmin "社区管理员" ; "replenisher": "补货员"
                var role = this.user.curRoleCode
                var userArea = res.obj.userArea
                var townList = [].concat(this.defaultOption)
                if(role=='communityAdmin' || role=="replenisher"){
                    var g = _.groupBy(userArea, 'town')
                    for(var k in g){
                        var tmp = JSON.parse(JSON.stringify(g[k][0]))
                        tmp.children = [{hospital: '', hospitalName: '全部'}].concat( g[k])
                        townList.push(tmp)
                    }
                    this.townList = townList
                } else {
                    if(role == 'regionAdmin'){
                        userArea.forEach(v => {
                            v.children = []
                        });
                        this.townList = townList.concat(userArea) 
                    } else if(role=='saasAdmin'){
                        await medicineAbinetApi
                            .baseTownList({ filters: "city=350200"})//写死厦门市
                            .then(res => {
                                console.log('baseTownList', res)
                                if (res.status == 200) {
                                    var detailModelList = res.detailModelList;
                                    detailModelList.forEach((item) => {
                                        item.town = item.code
                                        item.townName = item.name
                                        item.children = [];
                                    });
                                    this.townList = townList.concat(detailModelList) 
                                }
                            });
                    }
                }
                this.loadChildren()
            });
        },
        async loadChildren(){
            var item = this.townList[this.activeKey]
            if(!item.children || !item.children.length){
                await medicineAbinetApi
                    .findOrgList({ code: item.town, paeg: 1, pageSize: 999 })
                    .then(res => {
                        console.log('findOrgList', res)
                        if (res.status == 200) {
                            res.detailModelList.forEach(v=>{
                                v.hospitalName = v.name
                                v.hospital = v.code
                            })
                            item.children = [{hospital: '', hospitalName: '全部'}] .concat (res.detailModelList)
                        }
                    })
                    .catch(err=>{
                        item.children = []
                    })
            }
            this.communityList = item.children
        },
        onSelect(item){
            console.log('this.selcommunity', item)
            this.selcommunity = item;
            this.drowMenuShow = false;
            this.refreshData()
        },
        gotoDeviceList(networkStatus){
            var p = this.getTownUrlParams()
            p.networkStatus = networkStatus
            this.gotoUrl('/device/index', p)
        },
        toOrderPage(){
            var p = this.getTownUrlParams()
            p.sellState = 0
            this.gotoUrl('/order/list', p)
        },
        getTownUrlParams(){
            var p = {}
            if(this.selcommunity){
                if(this.selcommunity.hospital===''){
                    var item = this.townList[this.activeKey]
                    if(item.town === ''){
                    } else {
                        p.town = item.town;
                        p.townName = item.townName;
                    }
                } else {
                    var item = this.townList[this.activeKey]
                    p.town = item.town;
                    p.townName = item.townName;
                    p.hospital = this.selcommunity.hospital
                    p.hospitalName = this.selcommunity.hospitalName
                }
            }
            return p 
        }
    },
}
</script>
<style lang="scss" scoped>
.index-wrap {
	background: url('../../assets/images/index_banner.png') no-repeat;
	background-size: 100%;
	.panel{
		width: 345px;
		background-color: #ffffff;
		box-shadow: 0px 2px 10px 0px 
			rgba(0, 0, 0, 0.15);
		border-radius: 5px;
		margin: 0 auto;
		.drop-sel{
            background-color: rgba($color: #000000, $alpha: 0.05);
            border-radius: 12px;
            position: relative;
            .sel-body{
                width: 60px;
                left: 0;
                position: absolute;
                box-shadow: 2px 3px 8px 0px 
                    rgba(0, 0, 0, 0.15);
                border-radius: 11px;
                background-color: rgba($color: #ffff, $alpha: 0.8);
                text-align: center;
                padding: 10px 0;
                top: 30px;
                z-index: 1;
            }
        }
		&.sbzl{
			.van-col {
				position: relative;
				&::after{
					content: "";
					width: 1px;
					height: 41px;
					background-color: #e7e7e7;
					right: 0;
					position: absolute;
					top: 2px;
				}
				&:last-child{
					&::after{
						display: none;
					}
				}
			}
		}
		&.cygn{
			.van-col{
				padding: 10px 0;
				img{
					display: block;
					width: 40px;
					height: 40px;
					margin: 0 auto;
				}
			}
			
		}
	}
}
@import "./scss/index.scss";
</style>

+ 327 - 0
mini-pro-web/src/views/index/scss/index.scss

@ -0,0 +1,327 @@
.index-wrap {
	background: url('../../assets/images/index_banner.png') no-repeat;
    background-size: 100%;
    padding-top:20px;
    .home-text{
        width:375px;
        height:44px;
        line-height:44px;
        text-align:center;
        color:#fff;
    }
    .select{
        width: 345px;
        height:30px; 
        margin: 0 auto;
        position: relative;
        z-index: 5;
        .drop-menu{
            position: relative;
            .van-sidebar-item--select::before{
                background-color: #17b3ec;
            }
            .drop-menu-title{
                border-radius: 5px;
                padding: 5px 15px;
                background: #fff;
                border: 1px solid #e1e1e1;
                text-align: left;
                .van-icon{
                    position: absolute;
                    right: 10px;
                    top: 8px;
                }
            }
            .drop-menu-area{
                background: #f7f8fa;
                margin-top: 9px;
                position: absolute;
                width: 100%;
                left: 0;
                display: none;
                border: 1px solid #e1e1e1;
                border-radius: 5px;
                // border-bottom-left-radius: 5px;
                // border-bottom-right-radius: 5px;
                height: calc(100% - 40px);
                z-index: 5;
                .drop-menu-area-right{
                    height: 100%;
                    overflow-y: auto;
                    background: #fff;
                    -webkit-box-flex: 1;
                    >div{
                        padding: 10px 15px;
                        // border-bottom: 1px solid #e1e1e1;
                        &:last-child{
                            border-bottom: 0;
                        }
                    }
                }
            }
            &.active{
                height: calc(100vh - 49px);
                .drop-menu-area{
                    display: -webkit-box;
                }
               .drop-menu-title{
                   color: #17b3ec;
                //    border-bottom-left-radius: 0;
                //    border-bottom-right-radius: 0;
                //    border-bottom: 1px solid #fff;
                    .van-icon{
                        transform: rotate(-180deg);
                    }
                } 
            }
        }
    }
	.panel{
		width: 345px;
		background-color: #ffffff;
		box-shadow: 0px 2px 10px 0px 
			rgba(0, 0, 0, 0.15);
		border-radius: 5px;
		margin: 0 auto;
		.drop-sel{
            background-color: rgba($color: #000000, $alpha: 0.05);
            border-radius: 12px;
            position: relative;
            .sel-body{
                width: 60px;
                left: 0;
                position: absolute;
                box-shadow: 2px 3px 8px 0px 
                    rgba(0, 0, 0, 0.15);
                border-radius: 11px;
                background-color: rgba($color: #ffff, $alpha: 0.8);
                text-align: center;
                padding: 10px 0;
                top: 30px;
                z-index: 1;
            }
        }
        .box-flex-c{
            display: flex;
            justify-content:space-between;
        }
		&.sbzl{
            .Online{
                width:80px;
                height:80px;
                background:#2cc3f9;
                border-radius:5px;
            }
            .total{
                width:124px;
                height:80px;
                background:#42e5d4;
                border-radius:5px;
            }
            .offline{
                width:80px;
                height:80px;
                background:#fc87ba;
                border-radius:5px;
            }
            .equipment-num{
                width:100%;
                text-align:center;
                margin-top:20px;
                font-size:25px;
                color:#fff;
            }
            .equipment-text{
                width:100%;
                text-align:center;
                margin-top:10px;
                font-size:12px;
                color:#fff;
            }
		}
		&.cygn{
            .col{
                height:60px;
                text-align: center;
                position: relative;
                .operations-num{
                    font-size:20px;
                    color:#17b3ec;
                }
                .operations-text{
                    font-size:12px;
                    color:#666666;
                    span{
                        width:18px;
                        height:16px;
                        .img{
                            width:18px;
                            height:16px;
                            margin-right:5px;
                            position:relative;
                            top:2px;
                        }
                    }
                }
            }
            .col-t{
                padding-top:20px;
            }
            .col-tl::after{
                content:"";
                position:absolute;
                top:0;
                right:0;
                display:inline-block;
                width:1px;
                height:40px;
                background:#ccc;
            }
            .col-bl::after{
                content:"";
                position:absolute;
                top:20px;
                right:0;
                display:inline-block;
                width:1px;
                height:40px;
                background:#ccc;
            }
        }
        &.medicine{
            position:relative;
            .time{
                width:202px;
                height:28px;
                border:1px solid #ccc;
                border-top-left-radius:28px;
                border-bottom-left-radius:28px;
                border-top-right-radius:28px;
                border-bottom-right-radius:28px;
                .ul{
                    width: 100%;
                    li{
                        box-sizing: border-box;
                        float:left;
                        width: calc(100% / 5);
                        height:28px;
                        text-align:center;
                        line-height:28px;
                        color:#17b3ec;
                        cursor: pointer;
                    }
                    li:first-child{
                        border-top-left-radius:28px;
                        border-bottom-left-radius:28px;
                    }
                    li:last-child{
                        border-top-right-radius:28px;
                        border-bottom-right-radius:28px;
                    }
                    .border-r{
                        border-right:1px solid #ccc;
                    }
                    .li-bag{
                        background-color:#17b3ec;
                        color:#fff;
                    }
                }
            }
            .medicine-b-l{
                width:130px;
                height:70px;
                border-radius:5px;
                background:url("../../assets/images/quyaochishu_img.png");
                background-size: 100%;
                display:inline-block;
                position:relative;
                .medicine-b-g-num{
                    font-size:30px;
                    color:#fff;
                    position:absolute;
                    top:20px;
                    left:12px;
                    span{
                        font-size:12px;
                        position:relative;
                        left:-8px;
                    }
                }
            }
            .prescription{
                background:url("../../assets/images/chufangdan_img_01.png");
                background-size: 100%;
            }
            .care{
                width:120px;
                height:20px;
                line-height:20px;
                text-align:right;
                font-size:14px;
                position:absolute;
                bottom:30px;
                right:20px;
            }
            .scan{
                width:120px;
                height:20px;
                line-height:20px;
                text-align:right;
                font-size:14px;
                position:absolute;
                bottom:58px;
                right:20px;
            }
            .prescription-num{
                width:120px;
                height:20px;
                line-height:20px;
                text-align:right;
                font-size:14px;
                // background:red;
                position:absolute;
                bottom:47px;
                right:20px;
            }
            .sales-data{
                width:100%;
                height:63px;
                line-height:20px;
                // background:red;
                display: flex;
                justify-content:space-between;
                div{
                    font-size:14px;
                    color:#666666;
                }
                div:first-child{
                    font-size:20px;
                    color: #ff9600;
                }
                span{
                    color: #17b3ec;
                }
            }
            .sales-chart{
                width:100%;
                height:169px;
                padding-bottom:20px;
            }
        }
    }
    .mt10{
        margin-top:10px;
    }
    .home-bottom{
        width:100%;
        height:55px;
    }
    .mask{
        width: 100vh;
        height: 100vh;
        position: fixed;
        background-color: rgba($color: #000000, $alpha: 0.3);
        z-index: 4;
        top: 0;
    }
}

+ 1 - 1
mini-pro-web/src/views/login/FotgetPassword.vue

@ -154,7 +154,7 @@ export default {
                sendCaptcha({
                    type: 2, // 2 找回密码
                    username: this.data.mobile,
                    client_id: this.$root.clientId?this.$root.clientId:process.env.VUE_APP_CLIENTID,
                    client_id: this.$store.getters.clientId,
                    wxId: process.env.VUE_APP_WXID
                }).then((res) => {
                    if(res.status == 200) {

+ 6 - 37
mini-pro-web/src/views/login/Login.vue

@ -63,7 +63,7 @@
</template>
<script>
import { getPublicKey, login, imgCaptcha, sendCaptcha ,findOneUser} from "@/api/login";
import { getPublicKey, login, imgCaptcha, sendCaptcha ,findOneUserFormat} from "@/api/login";
import JSEncrypt from "@/utils/jsencrypt";
import ValidatorUtils from '@/utils/validator'
import { setTimeout } from 'timers';
@ -177,7 +177,7 @@ export default {
                sendCaptcha({
                    type: 1, // 1 登录
                    username: this.data.mobile?this.data.mobile:this.data.idcord,
                    client_id: this.$store.getters.clientId?this.$store.getters.clientId:process.env.VUE_APP_CLIENTID,
                    client_id: this.$store.getters.clientId,
                    wxId: process.env.VUE_APP_WXID
                }).then((res) => {
                    if(res.status == 200) {
@ -263,7 +263,6 @@ export default {
                }
                
                if (res && res.status == 200) {
                   
                    var encrypt = new JSEncrypt()
                    encrypt.setPublicKey(res.obj.publicKey)
                    p = {
@ -284,7 +283,7 @@ export default {
                }
            } else {
                p = {
                    client_id: this.$store.getters.clientId?this.$store.getters.clientId:process.env.VUE_APP_CLIENTID,
                    client_id: this.$store.getters.clientId,
                    username: this.data.mobile?this.data.mobile:this.data.idcord,
                    login_type: 1, // 1-平台管理员  2-医生登录  3-患者登录
                    captcha: this.data.msgCode,
@ -313,40 +312,9 @@ export default {
                    this.$store
                        .dispatch("SetLoginUser", userInfo)
                        .then(() => {
                            findOneUser({
                            findOneUserFormat({
                                id: userInfo.id
                            }).then(res2 => {
                                // "saasAdmin": "管理员"; regionAdmin" "区域管理员" ; communityAdmin "社区管理员" ;  "  "replenisher": "补货员"
                                var temArr = ['saasAdmin', 'regionAdmin', 'communityAdmin', 'replenisher']
                                var roleList = _.map(res2.obj.role, v=>{
                                    return {
                                        id: v.id,
                                        code: v.code,
                                        name: v.name
                                    }
                                })
                                roleList = _.sortBy(roleList, v=>{
                                    return temArr.indexOf(v.code)
                                })
                                // var userArea = _.map(res2.obj.userArea, v=>{
                                //     return {
                                //         id: v.id,
                                //         city: v.city,
                                //         cityName: v.cityName,
                                //         town: v.town,
                                //         townName: v.townName,
                                //         hospital: v.hospital,
                                //         hospitalName: v.hospitalName,
                                //     }
                                // })
                                var curRole = roleList[0]
                                var userInfo2 = {
                                    roleList,
                                    // userArea,
                                    curRoleCode: curRole.code,
                                    curRoleName: curRole.name
                                }
                            }).then(userInfo2 => {
                                userInfo = _.assignIn(userInfo, userInfo2);
                                this.$store
                                    .dispatch("SetLoginUser", userInfo)
@ -362,6 +330,7 @@ export default {
                            console.error(err)
                            this.$toast.clear()
                        })
                        // console.log('userinfo',userInfo)
                } else {
                    this.$toast.clear()
                    this.$toast(result.status==1300? "验证码错误" : result.message);

+ 2 - 2
mini-pro-web/src/views/login/Register.vue

@ -161,7 +161,7 @@ export default {
                this.countdownSubtract();
                sendCaptcha({
                    username: this.data.mobile,
                    client_id: this.$root.clientId?this.$root.clientId:process.env.VUE_APP_CLIENTID,
                    client_id: this.$store.getters.clientId,
                    wxId: process.env.VUE_APP_WXID
                }).then((res) => {
                    if(res.status == 200) {
@ -268,7 +268,7 @@ export default {
                captcha: this.data.msgCode,
                openid: this.user.openid,
                wxId: process.env.VUE_APP_WXID,
                client_id: this.$store.getters.clientId?this.$store.getters.clientId:process.env.VUE_APP_CLIENTID,
                client_id: this.$store.getters.clientId,
                login_type: 3, // 1-平台管理员  2-医生登录  3-患者登录
                idcard: this.data.idCard,

+ 53 - 0
mini-pro-web/src/views/machine/components/Dialog.vue

@ -0,0 +1,53 @@
<template>
	<div class="machine-index-dialog">
		<van-popup v-model="show" :close-on-click-overlay="false">
			<div class="fs-14 c-646566 tc pt20 pb20">
				打印完成
			</div>
			<div class="btn tc  fs-16 c-17b3ec">
				<van-button @click="close" type="default" block>返回上一页({{times}}s)</van-button>
			</div>
		</van-popup>
	</div>
</template>
<script>
var countDownFunc
export default {
  	data() {
    	return {
			show: true,
			times: 30
    	}
  	},
	mounted(){
		this.countDown()
	},
  	methods: {
		countDown(){
			this.times = 30
			countDownFunc = setInterval(()=>{
				if(this.times === 0){
					this.close()
				}
				this.times--
			}, 1000)
		},
		close(){
			clearInterval(countDownFunc)
			this.$emit('back')
		}
    },
}
</script>
<style lang="scss" scoped>
.machine-index-dialog {
	.van-popup {
		border-radius: 10px;
		width: 70vw;
		.van-button{
			border: 0;
			color: #17b3ec;
		}
	}
}
</style>

+ 272 - 81
mini-pro-web/src/views/machine/index.vue

@ -1,8 +1,8 @@
<template>
	<div class="machine-index" >
		<div v-show="step==3&&rsType!=3&&!inOut" class="back-btn" @click="onPrev">
		<div v-show="step==2 || (step==3&&rsType!=3&&!inOut)" class="back-btn" @click="onPrev">
			<img src="./img/fanhui_icon.png" alt="">
			<span>{{times}}s</span>
			<span v-if="rsType!=4">{{times}}s</span>
		</div>
		<div v-show="step===0" class="tc">
@ -81,11 +81,13 @@
			</template>
		</div>
		<Dialog ref="Dialog" v-if="showPrintComplete" @back="onPrev"/>
		<Scan @onComplete="onComplete" v-show="step==2" @onBack="step=1"/>
		<Result @showOrderDetail="showOrderDetail" @outDrug="sendShipment" @onPrint="SetPrintPage" :rsType.sync="rsType" :orderList="orderList" :orderdetail="orderdetail" v-show="step==3" @onBack="step=2" @onBackIndex="step=1"/>
		<Result @showOrderDetail="checkCardNo" @outDrug="sendShipment" @onPrint="SetPrintPage" :rsType.sync="rsType" :orderList="orderList" :orderdetail="orderdetail" v-show="step==3" @onBack="step=2" @onBackIndex="step=1"/>
	</div>
</template>
<script>
import Dialog from './components/Dialog.vue';
import Scan from './components/Scan.vue';
import Result from './components/Result.vue';
import medicineAbinetApi from '@/api/api-medicineAbinet'
@ -94,11 +96,12 @@ export default {
	name: "machineIndex",
	components: {
		Scan,
		Result
		Result,
		Dialog
  	},
  	data() {
    	return {
			isErr: 0,
			isErr: 0, //1设备维护  2正常使用
			deviceNum: this.$route.query.deviceNum || '',//14912202107000001500000000000000    14912202111000001000000000000000
			step: 0, //0启动页  1首页  2扫码页  3订单页
			curImg: '',
@ -121,13 +124,22 @@ export default {
			orderList: [],
			times: 30,
			shippingType: '', //取药方式(1、扫码,2、医保卡)
			inOut: false
			inOut: false,
			eventName: '',
			showPrintComplete: false,
			nextOrderDetail: '',
			oldCardNo: '',
			reconnect: false,
    	}
  	},
	watch:{
		step(n){
			if(n!=3){
			if(n==2){
				clearInterval(countDownFunc)
				this.countDown()
			}else if(n!=3){
				this.rsType = 0
				this.oldCardNo = ''
			}
		},
		rsType(n){
@ -143,28 +155,36 @@ export default {
			this.path = "ws://yik.ab-inbev.vip/c/websocket/"
		} else {
			//正式线
			this.path = "wss://zb.xmtyw.cn/cabinet/websocket/"
			// this.path = "wss://zb.xmtyw.cn/cabinet/websocket/"
			this.path = process.env.VUE_APP_MACHINE_SOCKET_URL
		}
		if(this.deviceNum){
			this.init(1)
		}
		window.SetPrintPage = this.SetPrintPage
		window.vm = this
	},
  	methods: {
		onPrev(){
			if(this.rsType == 5){
			this.nextOrderDetail = ''
			this.showPrintComplete = false
			if(this.step == 2){
				this.step = 1
			} else if(this.rsType==1 || this.rsType==2 || this.rsType==4){
				var orderLen = this.orderList&&this.orderList.length>1
				if(orderLen){
					if(this.rsType==4){
						this.orderList.splice(this.orderList.indexOf(this.orderInfo), 1)
					}
					this.rsType = 5
				} else {
			} else {
				if(this.rsType == 5){
					this.step = 1
				}
			} 
				} else if(this.rsType==1 || this.rsType==2 || this.rsType==4){
					var orderLen = this.orderList&&this.orderList.length>1
					if(orderLen){
						if(this.rsType==4){
							this.orderList.splice(this.orderList.indexOf(this.orderInfo), 1)
						}
						this.rsType = 5
					} else {
						this.step = 1
					}
				} 
			}
		},
		devinfoAdvList(){
			var p = {
@ -198,6 +218,7 @@ export default {
			this.$toast.clear()
            this.$loading('加载中..')
			this.shippingType = pickUpNum? 1 : 2
			this.oldCardNo = cardNum || ''
            let p = {
                deviceId: this.deviceNum, //设备编号
				pickUpNum, //取药码
@ -207,7 +228,8 @@ export default {
			// p = {
			// 	deviceId: this.deviceNum, //设备编号
			// 	cardNum: 'DD4517690'
			// 	cardNum: '',
			// 	ehcCard: "2AA15E2786973077D40FF5DEFFB5E7B12D79E3BD50BE59F22559FF361667E22C:0:445D0CE646F8F9DFEF648D36910287B5:3502A0001GZHA0002"
			// }
            console.log('params', p)
            medicineAbinetApi
@ -224,7 +246,7 @@ export default {
								list.forEach(v=>{
									var allPrice = 0
									v.drugList.forEach(d=>{
										allPrice += d.price * Number(d.quantity)
										allPrice += d.price * ((d.quantity&&Number(d.quantity)) || 1)
									})
									v.price = allPrice.toFixed(2)
								})
@ -276,6 +298,10 @@ export default {
                })
        },
		init: function(type) {
			if(this.reconnect === true){
				this.reconnect = 1
			}
			if(!this.deviceNum){
				return
			}
@ -302,24 +328,30 @@ export default {
			}
		},
		open: function() {
			if(this.reconnect===1){
				this.$toast('服务器重连成功')
				this.reconnect = false
			}
			console.log("socket连接成功")
			this.heartbit()
		},
		error: function() {
			this.$dialog.alert({
				title: '',
				message: '连接服务器失败',
				confirmButtonText: "重试"
			})
			.then(()=>{
				this.init()
			})
			console.log("连接错误")
			this.reconnectTimeout()
			return
			// this.socket.close()
		},
		getMessage: function(msg) {
			console.log(msg.data)
			//有收到消息后 重置重连定时器时间
			// this.reconnectTimeout()
			var msgobj = JSON.parse(msg.data)
			if (msgobj.type == 'ShipInfo') {
				if(!this.inOut){
					//有可能前端15秒已超时  但是后端还没超时  等了1分钟才返回数据 
					return
				}
				var item = this.orderdetail[this.currindex]
				if (msgobj.mess == ( item.layerNo +";"+ item.wayerNo) ) {
					this.updateOrderOutStatus(item.id, 2, msgobj.mess)
@ -350,7 +382,6 @@ export default {
						})
				}
			} else if (msgobj.type == 'BarCodeInfo') {
				debugger
				if (msgobj.mess.indexOf("异常") != -1) {
					this.$toast(msgobj.mess)
					console.log(msgobj.mess)
@ -370,18 +401,53 @@ export default {
					return
				}
				this.clearReadCardCountDown()
				if (msgobj.mess.indexOf("异常") != -1 || msgobj.mess.indexOf("读取信息失败") != -1) {
					this.$toast(msgobj.mess)
					return
				try{
					if (msgobj.mess.indexOf("异常") != -1 || msgobj.mess.indexOf("读取信息失败") != -1) {
						if(this.nextOrderDetail){
							this.$toast({
								forbidClick: true, // 禁用背景点击
								message: msgobj.mess,
								onClose: ()=>{
									this.onPrev()
								}
							});
						} else {
							this.$toast(msgobj.mess)
						}
						return
					}
					var arr = msgobj.mess.split("\n");
					var json = {}
					arr.forEach(v => {
						var tmp = v.split(":")
						json[tmp[0]] = tmp[1]
					});
					var cardNo = json['卡号']
					if(this.nextOrderDetail){
						if(cardNo != this.oldCardNo){
							this.$toast({
								forbidClick: true, // 禁用背景点击
								message: "医保卡信息不匹配,请重新操作",
								onClose: ()=>{
									this.onPrev()
								}
							});
						} else {
							this.$toast.clear()
							var order = this.nextOrderDetail
							this.nextOrderDetail = ''
							this.showOrderDetail(order)
						}
						return
					}
					this.checkOrderAndReturn({cardNum: cardNo})
				}catch(e){
					console.error(e)
				}
				var arr = msgobj.mess.split("\n");
				var json = {}
				arr.forEach(v => {
					var tmp = v.split(":")
					json[tmp[0]] = tmp[1]
				});
				this.checkOrderAndReturn({cardNum: json['卡号']})
			} else if(msgobj.type == 'PrintComplete'){
				this.showPrintComplete = true
				return
				this.$dialog.alert({
					title: '',
					message: '打印完成',
@ -389,8 +455,12 @@ export default {
				}).then(() => {
					this.onPrev()
				});
			} else if(msgobj.type == 'PageRload'){
				location.reload(true)
			} else if(msgobj.type == 'heart'){
				if(this.heartbitTimeout){
					clearTimeout(this.heartbitTimeout)
				}
			} else {
				this.checkNextEvent(msgobj.type)
			}
			// var obj = {
@ -403,14 +473,26 @@ export default {
			this.$loading('读取中..')
			this.clearReadCardCountDown()
			readCardCountDown = setTimeout(()=>{
				this.$toast('读取医保卡失败')
			}, 10 * 1000)
				if(this.nextOrderDetail){
					this.$toast.loading({
						duration: 0,
						forbidClick: true, // 禁用背景点击
						loadingType: 'loading',
						message: "读取医保卡超时",
						onClose: ()=>{
							this.onPrev()
						}
					});
				} else {
					this.$toast('读取医保卡超时')
				}
			}, 20 * 1000)
			var obj = {
				type: "ReadCard",
				mess: ""
			}
			this.socket.send(JSON.stringify(obj));
			this.send(obj);
		},
		sendShipment: function() {
@ -434,15 +516,14 @@ export default {
				layerNo: row.layerNo,
				wayerNo: row.wayerNo
			}
			this.socket.send(JSON.stringify(obj));
			this.send(obj);
		},
		send: function() {
			var obj = {
				type: "读取设备功能列表",
				mess: "",
				layerNo: this.layerNo,
				wayerNo: this.wayerNo,
		send: function(obj) {
			if(obj.type != 'heart'){
				//发送消息时  重置重连定时器时间
				// this.reconnectTimeout()
			}
			
			this.socket.send(JSON.stringify(obj));
		},
		send2: function() {
@ -450,31 +531,84 @@ export default {
				type: "读取设备功能列表",
				mess: ""
			}
			this.socket.send(JSON.stringify(obj));
			this.send(obj);
		},
		close: function() {
			console.log("socket已经关闭")
			this.reconnectTimeout()
			return
			this.clearHeartbit()
			if(!this.forceClose){
				console.log("socket已经关闭")
				this.init()
				this.reconnect = true
				this.$loading('服务器异常断开,正在重连..')
				setTimeout(()=>{
					this.init()
				}, 2000)
			}
			this.forceClose = false
		},
		reconnectTimeout(){
			if(this.reconnect === true){
				return
			}
			this.clearHeartbit()
			if(!this.forceClose){
				this.reconnect = true
				this.$loading('服务器异常断开,正在重连..')
				setTimeout(()=>{
					this.init()
				}, 2000)
			}
			this.forceClose = false
			return
			if(this.reconnectInterval){
				clearInterval(this.reconnectInterval)
			}
			this.reconnectInterval = setInterval(()=>{
				if(this.socket){
					this.forceClose = true
					this.socket.close()
				}
				setTimeout(()=>{
					this.init()
				}, 200)
			}, 5 * 60 * 1000 + 5000)
		},
		clearHeartbit(){
			if(this.heartbitInterval){
				clearInterval(this.heartbitInterval)
				this.heartbitInterval = undefined
			}
			if(this.heartbitTimeout){
				clearInterval(this.heartbitTimeout)
				this.heartbitTimeout = undefined
			}
		},
		heartbit(){
			this.clearHeartbit()
			this.heartbitInterval = setInterval(()=>{
				var obj = {
					type: "heart",
					mess: "",
				}
				this.socket.send(JSON.stringify(obj));
			}, 60 * 1000)
				this.send(obj);
				//8s没接收到heart的回执  就重连
				// this.heartbitTimeout = setTimeout(()=>{
				// 	this.socket.close()
				// }, 8000)
			}, 30 * 1000)
			// this.reconnectTimeout()
		},
		sendDeviceInfo: function() {
			var obj = {
				type: "ReadDevice",
				mess: ""
			}
			this.socket.send(JSON.stringify(obj));
			this.send(obj);
		},
		SetPrintPage: function() {
			// string type; //text 文本 |line 间隔行|barcode 条码|qrcode 二维码|reset 重置打印机 |nline 走纸【进行【
@ -496,7 +630,7 @@ export default {
			var printcon =[
				{type:"reset"},
				{type:"nline"},
				{type:"text", text:"智能药房\n小票凭据\n",nLan:0,nOrgx:-2,nWidthTimes:0,nHeightTimes:0,FontType:0,nFontStyle:0},
				{type:"text", text:"智慧药房\n小票凭据\n",nLan:0,nOrgx:-2,nWidthTimes:0,nHeightTimes:0,FontType:0,nFontStyle:0},
				{type:"text", text:"--------------------------------\n",nLan:0,nOrgx:-2,nWidthTimes:0,nHeightTimes:0,FontType:0,nFontStyle:0},
			];
			var allPrice = 0, allcount = 0
@ -513,36 +647,35 @@ export default {
			}
			list.forEach(v=>{
				printcon.push({
					type:"text", text: (v.drugName)+"\n",nLan:0,nOrgx:-1,nWidthTimes:0,nHeightTimes:0,FontType:0,nFontStyle:0
					type:"text", text: (v.drugName||v.goodsName)+"\n",nLan:0,nOrgx:-1,nWidthTimes:0,nHeightTimes:0,FontType:0,nFontStyle:0
				})
				printcon.push({
					type:"text", text: `单价:${v.price}元  数量:${v.quantity}\n药品编码:${v.drugCode}\n规格:${v.specif}\n剂型:${v.dosForm||''}\n`,nLan:0,nOrgx:-1,nWidthTimes:0,nHeightTimes:0,FontType:0,nFontStyle:0
					type:"text", text: `数量:${v.quantity}${v.unit}\n规格:${v.specif}\n用法:${v.useWay||''}  ${v.useDose||''}${v.unit||''}  ${v.useRate||''}`,nLan:0,nOrgx:-1,nWidthTimes:0,nHeightTimes:0,FontType:0,nFontStyle:0
				})
				printcon.push({type:"line"})
			})
			var {date, phone, num, remark, time, community, qrCodeContent, info} = this.orderInfo
			printcon.push({
				type:"text", text: `药品总价:${(allPrice).toFixed(2)}元\n药品数量:${allcount}\n订单金额:${allPrice.toFixed(2)}元\n`,nLan:0,nOrgx:-1,nWidthTimes:0,nHeightTimes:0,FontType:0,nFontStyle:0
			})
			var {date, phone, num, remark, time, community, qrCodeContent, info} = this.orderInfo
			// printcon.push({
			// 	type:"text", text: `药品总价:${(allPrice).toFixed(2)}元\n药品数量:${allcount}\n订单金额:${allPrice.toFixed(2)}元\n`,nLan:0,nOrgx:-1,nWidthTimes:0,nHeightTimes:0,FontType:0,nFontStyle:0
			// })
			var infoArr = (info&&info.split(',')) || [], 
				infoTextArr = []
			if(infoArr.indexOf("community") != -1){
				infoTextArr.push(`商家名称:${community}\n`)
				infoTextArr.push(`机构名称:${community}\n`)
			}
			if(infoArr.indexOf("phone") != -1){
				infoTextArr.push(`客服电话:${phone}\n`)
			}
			if(infoArr.indexOf("equNum") != -1){
				infoTextArr.push(`设备编号:${this.deviceNum}\n`)
			}
			// if(infoArr.indexOf("equNum") != -1){
			// 	infoTextArr.push(`设备编号:${this.deviceNum}\n`)
			// }
			if(infoArr.indexOf("orderNo") != -1){
				infoTextArr.push(`处方单号:${num}\n`)
			}
			if(infoArr.indexOf("shipTime") != -1){
				infoTextArr.push(`取药日期:${date}\n`)
				infoTextArr.push(`取药时间:${time}\n`)
				infoTextArr.push(`取药日期:${date} ${time}\n`)
			}
			if(infoTextArr&&infoTextArr.length){
				printcon.push({type:"text", text:"--------------------------------\n",nLan:0,nOrgx:-2,nWidthTimes:0,nHeightTimes:0,FontType:0,nFontStyle:0})
@ -558,9 +691,9 @@ export default {
			printcon.push({
				type:"text", text: `备注:${remark||""}\n`,nLan:0,nOrgx:-1,nWidthTimes:0,nHeightTimes:0,FontType:0,nFontStyle:0
			})
			if(qrCodeContent){
				printcon.push({type:"qrcode",text: qrCodeContent, nWidth:6,nVersion:0,nErrlevenl:4})
			}
			// if(qrCodeContent){
				printcon.push({type:"qrcode",text: qrCodeContent||"http://weixin.qq.com/r/hj9vd_LEAL9-raYU92qU", nWidth:6,nVersion:0,nErrlevenl:4})
			// }
			
			printcon.push({type:"nline"})
			printcon.push({type:"nline"})
@ -572,13 +705,13 @@ export default {
				type: "PrintPage",
				mess: JSON.stringify(printcon),
			}
			this.socket.send(JSON.stringify(obj));
			this.send(obj);
		},
		updateOrderOutStatus(shipmentLogId, status, msg){
			return new Promise((resolve, reject)=>{
				var p = {
					shipmentLogId,
					status,
					shipmentLogId: shipmentLogId || '',
					status: status || '',
					msg: msg || '',
					shippingType: this.shippingType //取药方式(1、扫码,2、医保卡)
				}
@ -586,6 +719,7 @@ export default {
				medicineAbinetApi
					.updateOrderOutStatus(p)
					.then(res=>{
						console.log('updateOrderOutStatus', res)
						if(res.status == 200){
							resolve()
							return
@ -614,10 +748,22 @@ export default {
					confirmButtonText: "返回首页"
				}).then(() => {
					this.step = 1
					if(this.eventName){
						var eventName = this.eventName
						this.eventName = ''
						this.checkNextEvent(eventName)
						return
					}
				});
				return
			}
			this.rsType = 4
			if(this.eventName){
				var eventName = this.eventName
				this.eventName = ''
				this.checkNextEvent(eventName)
				return
			}
		},
		countDown(){
			this.times = 30
@ -630,9 +776,7 @@ export default {
			}, 1000)
		},
		clearTimeoutInterval(){
			if(timeoutInterval){
				clearTimeout(timeoutInterval)
			}
			clearTimeout(timeoutInterval)
		},
		clearReadCardCountDown(){
			if(readCardCountDown){
@ -650,7 +794,7 @@ export default {
					.catch(err=>{
						console.error(err)
					})
			}, 15 * 1000)
			}, 30 * 1000)
		},
		videoSwipeChange(i){
			var video = this.$refs.videoSwipe.$el.getElementsByTagName("video")[i]
@ -670,6 +814,53 @@ export default {
				return
			}
			this.$refs.videoSwipe.next()
		},
		systemUpdate(){
			this.$loading('系统将进行更新,请勿操作')
			setTimeout(()=>{
				location.reload(true)
			}, 3000)
		},
		checkNextEvent(eventName){
			if(eventName == 'equ_normal'){
				//设备上线
				if(this.inOut){
					this.eventName = eventName
					return 
				}
				this.isErr = 2
			} else if(eventName == 'equ_maintenance'){
				//设备维护
				if(this.inOut){
					this.eventName = eventName
					return 
				}
				this.isErr = 1
			} else if(eventName == 'systemUpdate'){
				//系统更新
				if(this.inOut){
					this.eventName = eventName
					return 
				}
				this.systemUpdate()
			} else if(eventName == 'openDebug'){
				if(!window.vConsole){
					window.vConsole = new VConsole();
				}
			} else if(eventName == 'closeDebug'){
				if(window.vConsole){
					window.vConsole.destroy()
					window.vConsole = ""
				}
			}
		},
		checkCardNo(item){
			if(this.oldCardNo){
				this.nextOrderDetail = item
				this.sendReadCard()
			} else {
				this.showOrderDetail(item)
			}
		}
    },
	destroyed() {

+ 474 - 0
mini-pro-web/src/views/order/components/Filter.vue

@ -0,0 +1,474 @@
<template>
    <div class='order-list-filter'>
        <van-popup v-model="filterShow" position="right">
            <div class="fs-14 c-333  filter-panel">
                <div class="inner-content plr15">
                    <div class="filter-item-panel" v-if="hasCommunity">
                        <div class="ptb10">按社区</div>
                        <div class="drop-menu" :class="{active: drowMenuShow}">
                            <div class="drop-menu-title tc fs-14" @click="drowMenuShow=!drowMenuShow">
                                <span class="v-middle">{{selcommunity? (selcommunity.hospitalCode? selcommunity.hospitalName : selcommunity.townName) : '全部'}}</span>
                                <van-icon name="arrow-down" />
                            </div>
                            <div class="drop-menu-area kitbox">
                                <div class="drop-menu-area-left" v-if="townList&&townList.length">
                                    <van-sidebar v-model="activeKey">
                                        <van-sidebar-item v-for="(item, i) in townList" :key="i" :title="item.townName" />
                                    </van-sidebar>
                                </div>
                                <div class="drop-menu-area-right">
                                    <div v-for="(item, i) in communityList" :key="i" @click="selcommunity=item;drowMenuShow=false;">{{item.hospitalName}}</div>
                                </div>
                            </div>
                        </div>
                    </div>
                    
                    <div class="filter-item-panel" v-if="hasDate">
                        <div class="ptb10">按时间</div>
                        <div class="">
                            <van-tag @click="endDate='';startDate='';dateType=item.value" v-for="(item, i) in dateTypeOpts" :key="i" :class="{active: item.value===dateType}" type="primary" round>{{item.name}}</van-tag>
                            <van-tag @click="pickDate(1)" type="primary" round :class="{active: startDate}">{{(startDate&&$moment(startDate).format('YYYY-MM-DD')) || '请选择日期'}}</van-tag>
                            <van-tag class="small" type="primary" round>至</van-tag>
                            <van-tag @click="pickDate(2)" type="primary" round :class="{active: endDate}">{{(endDate&&$moment(endDate).format('YYYY-MM-DD')) || '请选择日期'}}</van-tag>
                        </div>
                    </div>
                    <div class="filter-item-panel" v-if="hasType">
                        <div class="ptb10">按类型</div>
                        <div class="">
                            <van-tag @click="state=item.value" v-for="(item, i) in stateOpts" :key="i" :class="{active: item.value===state}" type="primary" round>{{item.name}}</van-tag>
                        </div>
                    </div>
                    <template v-if="extendList&&extendList.length>0">
                    <div v-for="(citem, k) in extendList" :key="k" class="filter-item-panel" >
                        <div class="ptb10">{{citem.name}}</div>
                        <div class="">
                            <van-tag @click="citem.value=item.value" v-for="(item, i) in citem.opts" :key="i" :class="{active: item.value===citem.value}" type="primary" round>{{item.name}}</van-tag>
                        </div>
                    </div>
                    </template>
                </div>
                <div class="buttons kitbox ">
                    <div><van-button @click="reset" round block plain  size="small">重置</van-button></div>
                    <div><van-button @click="submit()" round block type="primary" color="#17b3ec" size="small">确定</van-button></div>
                </div>
            </div>
        </van-popup>
        <van-popup v-model="datePickerShow" position="bottom"  >
            <van-datetime-picker
                v-model="currentDate"
                @confirm="onPick"
                @cancel="datePickerShow=false"
                type="date"
                title=""
                :max-date="maxDate"
                :min-date="minDate"
            />
        </van-popup>
    </div>
</template>
<script>
import { findOneUser} from "@/api/login";
import medicineAbinetApi from '@/api/api-medicineAbinet'
export default{
    props: ['value', 'filterOpts', 'extendList'],
    data(){
        return {
            communityText: '全部',
            filterShow: false,
            currentDate: new Date(),
            minDate: this.$moment('2020-01-01').toDate(),
            maxDate: new Date(),
            datePickerShow: false,
            startDate: '',
            endDate: '',
            pickType: 1,
            totalCount: 0,
            totalMoney: 0,
            activeKey: 0,
            value1: '',
            defaultOption: [
                { townName: '全部', townCode: "", children: [{hospitalCode: '', hospitalName: '全部'}] },
            ],
            drowMenuShow: false,
            townList: [],
            communityList: [],
            selcommunity: '',
            stateOpts: [
                {name: '全部', value: ''},
                {name: '未取药', value: 0},
                {name: '已取药', value: 1},
                {name: '线下药房', value: -1},
                {name: '线下作废', value: -2},
            ],
            state: '',
            dateTypeOpts: [
                {name: '1个月内', value: 1},
                {name: '3个月内', value: 3},
                {name: '6个月内', value: 6},
            ],
            dateType: 3
        }
    },
    computed:{
        hasCommunity(){
            return !this.filterOpts || this.filterOpts.indexOf('community')!=-1
        },
        hasDate(){
            return !this.filterOpts || this.filterOpts.indexOf('date')!=-1
        },
        hasType(){
            return !this.filterOpts || this.filterOpts.indexOf('type')!=-1
        },
    },
    watch: {
        value(n){
            this.filterShow = n
        },
        filterShow(n){
            this.$emit('input', n)
        },
        activeKey(n){
            this.loadChildren()
        }
    },
    created() {
        var cur = this.$moment().subtract()
        var year = cur.years()
        this.dateTypeOpts.push(
            {name: '今年', value: year}
        )
        var year = cur.subtract(1, 'years').years()
        this.dateTypeOpts.push(
            {name: year+"年", value: year}
        )
        year = cur.subtract(1, 'years').years()
        this.dateTypeOpts.push(
            {name: year+"年", value: year}
        )
        this.getOrgList()
    },
    methods:{
        reset(){
            this.dateType = 3
            this.selcommunity = ''
            this.state = ''
            if(this.extendList && this.extendList.length){
                this.extendList.forEach(v=>{
                    v.value = v.defaultVal===undefined||v.defaultVal===''? '' : v.defaultVal
                })
            }
        },
        submit(selcommunity, state, allTime){
            console.log('selcommunity', this.selcommunity)
            var {dateType} = this
            if(selcommunity){
                this.selcommunity = selcommunity
            }
            if(state!==undefined){
                this.state = state
            }
            var startTime = '', endTime = ''
            if(allTime){
                this.dateType = ''
            } else {
                if(dateType==1 || dateType==3 || dateType==6){
                    startTime = this.$moment().subtract(dateType, 'months')
                    endTime = new Date()
                } else if(dateType > 2000){
                    var time = this.$moment().years(dateType)
                    startTime = time.startOf('year').toDate()
                    endTime = time.endOf('year').toDate()
                } else {
                    if(this.startDate){
                        startTime = this.startDate
                    }
                    if(this.endDate){
                        endTime = this.endDate
                    }
                }
            }
            
            this.$emit('onSubmit', {
                selcommunity: this.selcommunity,
                sellState: this.state,
                startTime,
                endTime,
                extendList: this.extendList
            })
            this.$emit('input', false)
        },
        pickDate(pickType){
            this.pickType = pickType
            this.currentDate = pickType ==1? this.startDate : this.endDate
            this.datePickerShow = true
        },
        onPick(){
            this.dateType = ''
            var date = this.$moment(this.currentDate).toDate()
            if(this.pickType ==1){
                this.startDate = date
            } else {
                this.endDate = date
            }
            this.datePickerShow = false
        },
        getOrgList(){
            findOneUser({
                id: this.user.id
            }).then(async res => {
                // "saasAdmin": "管理员"; regionAdmin" "区域管理员" ; communityAdmin "社区管理员" ; "replenisher": "补货员"
                var role = this.user.curRoleCode
                var userArea = res.obj.userArea
                var townList = [].concat(this.defaultOption)
                if(role=='communityAdmin' || role=="replenisher"){
                    var g = _.groupBy(userArea, 'town')
                    for(var k in g){
                        var tmp = JSON.parse(JSON.stringify(g[k][0]))
                        tmp.children = g[k]
                        townList.push(tmp)
                    }
                    this.townList = townList
                } else {
                    if(role == 'regionAdmin'){
                        userArea.forEach(v => {
                            v.children = []
                        });
                        this.townList = townList.concat(userArea) 
                    } else if(role=='saasAdmin'){
                        await medicineAbinetApi
                            .baseTownList({ filters: "city=350200"})//写死厦门市
                            .then(res => {
                                console.log('baseTownList', res)
                                if (res.status == 200) {
                                    var detailModelList = res.detailModelList;
                                    detailModelList.forEach((item) => {
                                        item.town = item.code
                                        item.townName = item.name
                                        item.children = [];
                                    });
                                    this.townList = townList.concat(detailModelList) 
                                }
                            });
                    }
                }
                this.loadChildren()
            });
        },
        async loadChildren(){
            var item = this.townList[this.activeKey]
            if(!item.children || !item.children.length){
                await medicineAbinetApi
                    .findOrgList({ code: item.town, paeg: 1, pageSize: 999 })
                    .then(res => {
                        console.log('findOrgList', res)
                        if (res.status == 200) {
                            res.detailModelList.forEach(v=>{
                                v.hospitalName = v.name
                                v.hospitalCode = v.code
                            })
                            item.children = [{hospitalName:'全部', hospitalCode: '', town: item.town, townName: item.townName}].concat(res.detailModelList) 
                        }
                    })
                    .catch(err=>{
                        item.children = []
                    })
            }
            this.communityList = item.children
        }
    },
}
</script>
<style lang='scss' scoped>
.order-list-filter{
    .top-banner{
        .search-date{
            background: #f2f3f5;
        }
        .date-item{
            width: 110px;
            text-align: center;
            padding: 5px 0;
            border: 1px solid #ccc;
            background: #fff;
            color: #333;
            border-radius: 30px;
        }
        .van-button--mini{
            height: 28px;
            width: 60px;
        }
        .drop-menu{
            position: relative;
            .van-sidebar-item--select::before{
                background-color: #17b3ec;
            }
            .drop-menu-title{
                padding: 10px 0;
                background: #fff;
                .van-icon{
                    transform: rotate(90deg);
                }
            }
            .drop-menu-area{
                position: absolute;
                width: 100%;
                left: 0;
                display: none;
                border-top: 1px solid #e1e1e1;
                height: calc(100% - 39px);
                .drop-menu-area-right{
                    height: 100%;
                    overflow-y: auto;
                    background: #fff;
                    -webkit-box-flex: 1;
                    >div{
                        padding: 10px 15px;
                        border-bottom: 1px solid #e1e1e1;
                        &:last-child{
                            border-bottom: 0;
                        }
                    }
                }
            }
            &.active{
                background: rgba($color: #000000, $alpha: .4);
                height: calc(100vh - 49px);
                .drop-menu-area{
                    display: -webkit-box;
                }
               .drop-menu-title{
                   color: #17b3ec;
                    .van-icon{
                        transform: rotate(-90deg);
                    }
                } 
            }
        }
    }
    .filter-panel{
        background: #fff;
        width: 90vw;
        height: 100vh;
        .inner-content{
            overflow-y: auto;
            height: calc(100% - 60px);
            .filter-item-panel{
                margin-top: 10px;
                &:first-child{
                    margin-top: 0;
                }
            }
        }
        .community-input{
            border: 1px solid #ccc;
            border-radius: 100px;
            line-height: 30px;
            padding: 0 15px;
            position: relative;
            padding-right: 40px;
            .van-icon{
                position: absolute;
                right: 10px;
                top: 50%;
                transform: translateY(-50%);
            }
        }
        .van-tag{
            width: 95px;
            text-align: center;
            background: rgb(242, 242, 242);
            color: #999;
            padding: 5px 0;
            justify-content: center;
            margin-bottom: 10px;
            margin-right: 10px;
            &:nth-child(3n){
                margin-right: 0;
            }
            &.active{
                background: #17b3ec;
                color: #fff;
            }
            &.small{
                width: 20px;
                background: #fff;
            }
        }
        .buttons{
            position: absolute;
            bottom: 15px;
            width: calc(100%);
            >div{
                width: 50%;
                padding: 0 15px;
            }
        }
        .drop-menu{
            position: relative;
            .van-sidebar-item--select::before{
                background-color: #17b3ec;
            }
            .drop-menu-title{
                padding: 5px 15px;
                background: #fff;
                border-radius: 30px;
                border: 1px solid #e1e1e1;
                text-align: left;
                .van-icon{
                    position: absolute;
                    right: 10px;
                    top: 8px;
                }
            }
            .drop-menu-area{
                margin-top: 10px;
                position: absolute;
                width: 100%;
                left: 0;
                display: none;
                border-top: 1px solid #e1e1e1;
                height: calc(100% - 39px);
                .drop-menu-area-right{
                    height: 100%;
                    overflow-y: auto;
                    background: #fff;
                    -webkit-box-flex: 1;
                    >div{
                        padding: 10px 15px;
                        border-bottom: 1px solid #e1e1e1;
                        &:last-child{
                            border-bottom: 0;
                        }
                    }
                }
            }
            &.active{
                height: calc(100vh - 49px);
                .drop-menu-area{
                    display: -webkit-box;
                }
               .drop-menu-title{
                   color: #17b3ec;
                    .van-icon{
                        transform: rotate(-180deg);
                    }
                } 
            }
        }
    }
}
</style>

+ 1 - 0
mini-pro-web/src/views/order/detail/components/DeviceInfo.vue

@ -2,6 +2,7 @@
    <div class='order-detail-device-info lh26 plr15 ptb10 break-all bgc-fff fs-14'>
        <div>出货设备:{{data.equName}}</div>
        <div>设备编号:{{data.equNum}}</div>
        <div>所属社区:{{data.community}}</div>
        <div>设备地址:{{data.deliveryAddress}}</div>
    </div>
</template>

+ 2 - 1
mini-pro-web/src/views/order/detail/components/DrugList.vue

@ -9,7 +9,8 @@
            </div>
            <div class="pl10 box-flex-1">
                <div class="ellipsis">{{item.goodsName}}</div>
                <div class="pt8">¥{{getMoney(item)}}</div>
                <div class="">规格:{{item.specif}}</div>
                <div class="">¥{{getMoney(item)}}</div>
            </div>
            <div class="kitbox box-v-middle pl15">x{{item.quantity}}</div>
        </div>

+ 2 - 1
mini-pro-web/src/views/order/detail/components/LogList.vue

@ -3,9 +3,10 @@
        <div v-for="(item, i) in list" :key="i" class="item lh26 plr15 ptb10 break-all bgc-fff fs-14 bb-e1e1e1">
            <div>出货货道: <span>{{item.layerNo}}行{{item.wayerNo}}列</span></div>
            <div class="kitbox">
                <div class="box-flex-1">商品名称: <span>{{item.drugName}}</span></div>
                <div class="box-flex-1">药品名称: <span>{{item.drugName}}</span></div>
                <div>x1</div>
            </div>
            <div>药品规格: <span>{{item.specif}}</span></div>
            <div>设备日志: <span>{{item.status==2? '(无异常)出货成功' : item.description}}</span></div>
            <div>设备名称: <span>{{item.equName}}</span></div>
            <div class="out-img"><span>出货图片: </span><img @click="preview(item.pic)" :src="setImgUrl(item.pic)" alt=""></div>

+ 2 - 2
mini-pro-web/src/views/order/detail/index.vue

@ -26,8 +26,8 @@
                <div>{{info.sellStateName}}</div>
            </div>
            <div class="row">
                <div>存取信息</div>
                <div>取药码 {{info.pickUpNum}}</div>
                <div>取药码</div>
                <div>{{info.pickUpNum}}</div>
            </div>
        </div>

+ 125 - 18
mini-pro-web/src/views/order/list.vue

@ -2,7 +2,22 @@
    <div class='order-list'>
        <van-sticky :offset-top="offsetTop">
            <div class="top-banner  fs-14  ">
                <div @click="drowMenuShow=false" class="kitbox pl15 search-date ptb10">
                <form action="/">
                    <van-search
                        v-model="searchText"
                        placeholder="订单号、手机号"
                        show-action
                        @search="onSearch"
                        shape="round"
                    >
                    <div slot="action" class="plr5">
                        <van-icon @click="filterShow=true" style="vertical-align: text-bottom;" color="#17b3ec" size="20px" name="filter-o" />
                    </div>
                    </van-search>
                </form>
                <!-- <div @click="drowMenuShow=false" class="kitbox pl15 search-date ptb10">
                    <div @click="pickDate(1)" class="date-item">{{$moment(startDate).format('YYYY-MM-DD')}}</div>
                    <div class="ptb5 plr10">至</div>
                    <div @click="pickDate(2)" class="date-item">{{$moment(endDate).format('YYYY-MM-DD')}}</div>
@ -25,9 +40,12 @@
                            <div v-for="(item, i) in communityList" :key="i" @click="selcommunity=item;drowMenuShow=false;onSearch()">{{item.hospitalName}}</div>
                        </div>
                    </div>
                </div>
                </div> -->
            </div>
        </van-sticky>
        
            <!-- searchPlaceholder="订单号、金额、手机号" -->
        <CustomList 
			ref="customList"
            :searchfun="false"
@ -35,20 +53,43 @@
			<div class="list plr15">
                <div @click="gotoUrl('./detail', {id: item.id})" v-for="(item, i) in list" :key="i" class="item plr15 c-333 fs-14">
                    <div class="kitbox ptb10 bb-e1e1e1">
                        <div class="box-flex-1 fs-14">{{item.prescribeNum}}</div>
                        <div v-if="item.sellState==1" class="c-17b3ec">{{item.sellStatusName}}</div>
                        <div v-else class="" >{{item.sellStatusName}}</div>
                        <div class="box-flex-1 fs-14">订单编号:{{item.prescribeNum}}</div>
                        <div v-if="item.sellState==1" class="c-17b3ec">{{item.sellStateName}}</div>
                        <div v-else class="" >{{item.sellStateName}}</div>
                    </div>
                    <div class="lh20 ptb10">
                        <div>来源机构:{{item.community}}</div>
                        <div>订单类型:{{item.orderTypeName || "线上订单"}}</div>
                        <div>开方时间:{{formatDatetime(item.prescribeTime)}}</div>
                        <div>存取信息:取药码 {{item.pickUpNum}}</div>
                        <div>取药码:{{item.pickUpNum}}</div>
                    </div>
                    <div class="ptb10 bt-e1e1e1">¥{{item.amount}}</div>
                </div>
            </div>
		</CustomList>
        <FilterPanel v-model="filterShow" @onSubmit="onSubmit" ref="Filter"/>
        <!-- <van-popup v-model="filterShow" position="right">
            <div class="fs-14 c-333 plr15 filter-panel">
                <div class="ptb10">按社区</div>
                <div class="ptb10">按时间</div>
                <div class="">
                    <van-tag type="primary" round>全部</van-tag>
                    <van-tag type="primary" round>标签</van-tag>
                    <van-tag type="primary" round>标签</van-tag>
                    <van-tag type="primary" round>标签</van-tag>
                </div>
                <div class="ptb10">按类型</div>
                <div class="">
                    <van-tag type="primary" round>全部</van-tag>
                    <van-tag type="primary" round>标签</van-tag>
                    <van-tag type="primary" round>标签</van-tag>
                </div>
            </div>
        </van-popup> -->
        <van-popup v-model="datePickerShow" position="bottom"  >
            <van-datetime-picker
                v-model="currentDate"
@ -66,19 +107,25 @@
                    共 {{totalCount}} 笔订单
                </div>
                <!-- <div class="box-flex-1 plr15 tr">
                    商品总金额 ¥{{totalMoney}}
                    药品总金额 ¥{{totalMoney}}
                </div> -->
            </div>
        </div>
    </div>
</template>
<script>
import FilterPanel from './components/Filter'
import medicineAbinetApi from '@/api/api-medicineAbinet'
import { findOneUser} from "@/api/login";
export default{
    name: 'orderList',
    components:{
        FilterPanel
    },
    data(){
        return {
            filterShow: false,
            searchText: '',
            list: [],
            currentDate: new Date(),
            maxDate: new Date(),
@ -99,7 +146,7 @@ export default{
            townList: [],
            communityList: [],
            selcommunity: '',
            
            sellState: '',
        }
    },
    watch: {
@ -108,20 +155,51 @@ export default{
        }
    },
    created() {
        this.getOrgList()
        
    },
    mounted(){
        var allTime = false
        if(this.$route.query.hospital||this.$route.query.town){
            this.selcommunity = {
                hospitalCode: this.$route.query.hospital||'',
                hospitalName: this.$route.query.hospitalName||'',
                town: this.$route.query.town||'',
                townName: this.$route.query.townName||'',
            }
        }
        if(this.$route.query.sellState!==''&&this.$route.query.sellState!==undefined){
            this.sellState = this.$route.query.sellState
            allTime = true
        }
        this.$refs.Filter.submit(this.selcommunity, this.sellState, allTime)
    },
    methods:{
        onLoad({page, pageSize, searchText}){
            var { startDate, endDate } = this
            var p = {
				startTime: startDate? this.$moment(startDate).format('YYYY-MM-DD 00:00:00') : '',
				endTime: endDate? this.$moment(endDate).format('YYYY-MM-DD 23:59:59') : '',
                userId: this.user.id,
				community: this.selcommunity? this.selcommunity.hospitalCode : '',
				// content: searchForm.content,
				// sellState: searchForm.sellStatus,
                page: page,
                size: pageSize
            var p 
            if(this.searchText){
                p = {
                    userId: this.user.id,
                    content: this.searchText,
                    page: page,
                    size: pageSize
                }
            } else {
                var town = '', community = ''
                if(this.selcommunity){
                    community = this.selcommunity.hospitalCode||this.selcommunity.hospital||''
                    town = community? '' : (this.selcommunity.town||'')
                }
                p = {
                    startTime: startDate? this.$moment(startDate).format('YYYY-MM-DD 00:00:00') : '',
                    endTime: endDate? this.$moment(endDate).format('YYYY-MM-DD 23:59:59') : '',
                    userId: this.user.id,
                    community,
                    town,
                    sellState: this.sellState,
                    page: page,
                    size: pageSize
                } 
            }
            console.log('params', p)
            medicineAbinetApi
@ -227,6 +305,13 @@ export default{
            }
            this.communityList = item.children
        },
        onSubmit(data){
            this.startDate = data.startTime
            this.endDate = data.endTime
            this.selcommunity = data.selcommunity
            this.sellState = data.sellState
            this.onSearch()
        }
    },
}
@ -330,6 +415,28 @@ export default{
    ::v-deep .van-list__placeholder{
        height: 40px;
    }
    .filter-panel{
        background: #fff;
        width: 90vw;
        height: 100vh;
        .van-tag{
            width: 95px;
            text-align: center;
            background: rgb(242, 242, 242);
            color: #999;
            padding: 5px 0;
            justify-content: center;
            margin-bottom: 10px;
            margin-right: 10px;
            &:nth-child(3n){
                margin-right: 0;
            }
            &.active{
                background: #17b3ec;
                color: #fff;
            }
        }
    }
}
</style>

+ 10 - 9
mini-pro-web/src/views/personal/index.vue

@ -50,17 +50,9 @@ export default{
        }
    },
    methods:{
        redirectToLogin() {
            let appId = process.env.VUE_APP_APPID,
                protocol = window.location.protocol,
                host = window.location.host,
                redirctWxAuthUrl = encodeURIComponent(`${protocol}//${host}${process.env.VUE_APP_PRE_PATH}/login`),
                wxAuthUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${redirctWxAuthUrl}&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect`
            
            location.replace(wxAuthUrl)
        },
        async logout(){
            await this.$store.dispatch('LogOut')
            console.log(this.$store.getters.user)
            this.gotoUrl('/login')
        },
    },
@ -77,4 +69,13 @@ export default{
        display: block;
    }
}
</style>
<style lang='scss'>
@supports(bottom: env(safe-area-inset-bottom)){
    .personal-index{
        .bot-btn{
            padding-bottom: env(safe-area-inset-bottom);
        }
    }
}
</style>

+ 2 - 2
mini-pro-web/src/views/replenishment/device/detail.vue

@ -8,7 +8,7 @@
                <div class="color-block ml10 red"></div>
                <span class="ml5 fs-12">故障</span>
            </div>
            <div><van-button @click="gotoUrl('/replenishment/start/deviceDetail', {deviceId: deviceId})" type="info" size="small">点击设置商品</van-button></div>
            <div><van-button @click="gotoUrl('/replenishment/start/deviceDetail', {deviceId: deviceId})" type="info" size="small">点击设置药品</van-button></div>
        </div>
        <div class="list ">
@ -27,7 +27,7 @@
                                <div class="ellipsis tc pt8">{{data.drugName}}</div>
                                <div class="tc pt5">¥{{data.price}}</div>
                            </template>
                            <div v-else class="ellipsis tc pt8 ">未设商品</div>
                            <div v-else class="ellipsis tc pt8 ">未设药品</div>
                        </div>
                    </div>
                </div>

+ 1 - 1
mini-pro-web/src/views/replenishment/device/list.vue

@ -15,7 +15,7 @@
                    <div class="lh20 ptb10 kitbox">
                        <div class="box-flex-1">
                            <div>药柜容量:{{item.capacity}}</div>
                            <div>商品库存:{{item.shangPinKuCun}}</div>
                            <div>药品库存:{{item.shangPinKuCun}}</div>
                            <div>设备所属:{{item.community}}</div>
                            <div>设备编号:{{item.equNum}}</div>
                        </div>

+ 6 - 6
mini-pro-web/src/views/replenishment/index.vue

@ -10,7 +10,7 @@
					<span class="ml5">台</span>
				</div>
				<div class="">
					<span class="v-middle">查看设备商品</span>
					<span class="v-middle">查看设备药品</span>
					<van-icon class="v-middle"  name="arrow" />
				</div>
			</div>
@ -23,18 +23,18 @@
		<div class="mt10"></div>
		<div class="panel plr15 c-fff fs-14">
			<div class=" pt15 ">
				<div class="fs-16 f-bold">缺货设备  |  实时</div>
				<div class="fs-16 f-bold">缺药设备  |  实时</div>
			</div>
			<div class="  pt10">
				<span class="fs-23">{{countObj.outCount}}</span>
				<span class="ml5">台</span>
			</div>
			<div class="pt10 ">
				以上统计的缺货设备为实时数据
				以上统计的缺药设备为实时数据
			</div>
			<div class="kitbox ptb10">
				<div class="box-flex-1 mr10">
					<van-button @click="gotoUrl('/replenishment/stockUp/deviceList')" plain block round size="small" type="info">去备货</van-button>
					<van-button @click="gotoUrl('/replenishment/stockUp/deviceList')" plain block round size="small" type="info">去备药</van-button>
				</div>
				<div class="box-flex-1 ml10">
					<van-button @click="gotoUrl('/replenishment/start/deviceList')" plain block round size="small" type="info">去补货</van-button>
@ -51,7 +51,7 @@
					<van-row class="">
						<van-col @click="gotoUrl('/replenishment/picking/list')" span="6" class="tc ">
							<div class="fs-23 c-17b3ec"><img src="@/assets/images/dingdanguanli.png" alt=""></div>
							<div class="fs-14 c-666 pt5">备货单</div>
							<div class="fs-14 c-666 pt5">药品申领</div>
						</van-col>
						<van-col @click="gotoUrl('/replenishment/record/list')" span="6" class="tc">
							<div class="fs-23 c-ff9526"><img src="@/assets/images/shebeiguanli.png" alt=""></div>
@ -80,7 +80,7 @@ export default {
				"saleTotal": 0,						//在售数
				"onlineRate": 0,					//在线率
				"onlineTotal": 0,						//在线设备数
				"outCount": 0 						//缺货设备数
				"outCount": 0 						//缺药设备数
			}
			
    	}

+ 2 - 2
mini-pro-web/src/views/replenishment/picking/detail.vue

@ -2,12 +2,12 @@
    <div class='replenishment-picking-detail fs-14'>
        <div class="list bgc-fff">
            <div class="row kitbox">
                <div class="box-flex-1 pl10">商品名称</div>
                <div class="box-flex-1 pl10">药品名称</div>
                <div class="tc">领料数量</div>
            </div>
            <div class="row kitbox" v-for="(item, i) in drugList" :key="i">
                <div class="box-flex-1 pl10 ellipsis">{{item.drugName}}</div>
                <div class="tc">{{item.claim}}</div>
                <div class="tc">{{item.claim || item.quantity}}</div>
            </div>
        </div>
    </div>

+ 82 - 26
mini-pro-web/src/views/replenishment/picking/list.vue

@ -1,16 +1,16 @@
<template>
    <div class='replenishment-picking-list'>
        <van-sticky :offset-top="offsetTop">
    <div class='replenishment-picking-list' :class="{'show-one': status, hasBotBanner: status==2}">
        <van-sticky :offset-top="offsetTop" v-if="!status">
            <van-tabs v-model="active" @change="onChange">
                <!-- <van-tab title="全部"></van-tab> -->
                <van-tab title="备货中"></van-tab>
                <van-tab title="备药中"></van-tab>
                <van-tab title="">
                    <div slot="title">
                        <van-badge v-if="waitCount" :content="waitCount">待领料</van-badge>
                        <span v-else>待领料</span>
                        <van-badge v-if="waitCount" :content="waitCount">待领药</van-badge>
                        <span v-else>待领药</span>
                    </div>
                </van-tab>
                <van-tab title="已领料"></van-tab>
                <van-tab title="已领药"></van-tab>
                <!-- <van-tab title="已驳回"></van-tab> -->
            </van-tabs>
        </van-sticky>
@ -21,10 +21,10 @@
			<div class="list plr15 pt10">
                <div @click="gotoDetail(item)" v-for="(item, i) in list" :key="i" class="item bgc-fff plr15 c-333 fs-14">
                    <div class=" ptb10 kitbox bb-e1e1e1">
                        <div class="box-flex-1 fs-14">备货单号:{{item.docNum}}</div>
                        <div class="box-flex-1 fs-14">药品申领单号:{{item.docNum}}</div>
                        <div class="">
                            <span v-if="active===0&&item.state==1" class="c-ff9526">备货中</span>
                            <span v-if="active===0&&item.state!=1" class="c-17b3ec">已备货</span>
                            <span v-if="active===0&&item.state==2" class="c-ff9526">未生成</span>
                            <span v-if="active===0&&item.state==1" class="c-17b3ec">已生成</span>
                            <span v-else-if="active===1" class="c-17b3ec">待领料</span>
                            <span v-else-if="active===2" class="c-999">已领料</span>
                            <!-- <span class="c-ff5e6c">已驳回</span> -->
@ -33,19 +33,19 @@
                    <div class="lh20 ptb10 kitbox">
                        <div class="box-flex-1">
                            <div class="row">
                                <div>补货员</div>
                                <div>设备管理员</div>
                                <div>{{item.replenishErName}}</div>
                            </div>
                            <div class="row">
                                <div>待补设备</div>
                            <!-- <div class="row">
                                <div>待入库设备</div>
                                <div>{{item.replenishEquName}}</div>
                            </div>
                            </div> -->
                            <div class="row">
                                <div>待补品类</div>
                                <div>待入库品类</div>
                                <div>{{item.replenishCate}}</div>
                            </div>
                            <div class="row">
                                <div>待补库存</div>
                                <div>待入库库存</div>
                                <div>{{item.replenishInventory}}</div>
                            </div>
                            <div class="row">
@ -60,25 +60,43 @@
                </div>
            </div>
		</CustomList>
        <div class="bot-banner" v-if="status==2">
            <div class="kitbox">
                <div class="box-flex-1 plr5"><van-button @click="gotoUrl('/replenishment/picking/outList', {deviceId: deviceId, status: 1})" block plain color="#17b3ec" size="small" type="primary" round>出库单列表</van-button></div>
                <div class="box-flex-1 plr5"><van-button @click="gotoUrl('/replenishment/stockUp/detail', {deviceId: deviceId})" block color="#17b3ec" size="small" type="primary" round>新增药品申领单</van-button></div>
            </div>
        </div>
    </div>
</template>
<script>
import medicineAbinetApi from '@/api/api-medicineAbinet'
export default{
    name: 'replenishmentDeviceList',
    name: 'replenishmentPickingList',
    data(){
        return {
            deviceId: this.$route.query.deviceId,
            list: [],
            active: 0,
            waitCount: 0
            waitCount: 0,
            status: ""
            
        }
    },
    created() {
        
        this.status = this.$route.query.status
        if(this.status){
            this.active = this.status==1 || this.status==2? 0 : 1
        }
    },
    methods:{
        $refreshData(){
            debugger
            this.$refs.customList.refresh(true)
        },
        onLoad({page, pageSize, searchText}){
            var p = {
                deviceId: this.deviceId,
				// startTime: startDate? this.$moment(startDate).format('YYYY-MM-DD 00:00:00') : '',
				// endTime: endDate? this.$moment(endDate).format('YYYY-MM-DD 23:59:59') : '',
				// content: searchForm.content,
@ -91,6 +109,9 @@ export default{
            var func;
            if(this.active === 0){
                func = medicineAbinetApi.replenishList
                if(this.status){
                    p.state = this.status
                }
            } else if(this.active === 1){
                p.receiveState = 0
                func = medicineAbinetApi.outboundOrderList
@ -121,15 +142,19 @@ export default{
            this.$refs.customList.refresh(true)
        },
        gotoDetail(item){
            var query = {
            }
            if(this.active===0){
                query.idUp = item.id
            if(this.status == 2){
                this.gotoUrl('/replenishment/stockUp/createOut', {deviceId: this.deviceId, upId: item.id})
            } else {
                query.idOut = item.id
                var query = {
                }
                if(this.active===0){
                    query.idUp = item.id
                } else {
                    query.idOut = item.id
                }
                this.gotoUrl('./detail', query)
            }
            this.gotoUrl('./detail', query)
        }
    },
}
@ -162,7 +187,7 @@ export default{
                display: -webkit-box;
                div{
                    &:first-child{
                        width: 60px;
                        width: 72px;
                        position: relative;
                        text-align: justify;
                        text-align-last: justify;
@ -182,6 +207,32 @@ export default{
    .custom-list{
        height: calc(100vh - 50px);
    }
    &.show-one{
        .van-tab{
            display: none;
        }
        .custom-list{
            height: calc(100vh - 52px);
        }
        &.hasBotBanner{
            ::v-deep .van-list__placeholder{
                height: 55px;
            }
        }
        .bot-banner{
            padding: 10px 5px;
            position: fixed;
            bottom: 0;
            width: 100%;
            left: 0;
            background: #fff;
            z-index: 3;
            >div{
                -webkit-box-flex: 1;
            }
        }
    }
}
</style>
<style lang="scss">
@ -190,6 +241,11 @@ export default{
        .custom-list {
            height: calc(100vh - 96px);
        }
        &.show-one{
            .custom-list{
                height: calc(100vh - 98px);
            }
        }
    }
}
</style>

+ 26 - 0
mini-pro-web/src/views/replenishment/picking/outList.vue

@ -0,0 +1,26 @@
<template>
    <PickingList/>
</template>
<script>
import PickingList from './list'
export default{
    name: 'replenishmentOutList',
    components: {
        PickingList
    },
    data(){
        return {
            
        }
    },
    created() {
       
    },
    methods:{
       
    },
}
</script>
<style lang='scss' scoped>
</style>

+ 4 - 4
mini-pro-web/src/views/replenishment/record/detail.vue

@ -6,7 +6,7 @@
                <template>
                    <div>补货时间:2020-08-24 17:15:19</div>
                    <div>设备编号:149122021070000</div>
                    <div>商品数量:2</div>
                    <div>药品数量:2</div>
                    <div>补货人员:张三</div>
                </template>
                <!-- <template>
@ -25,7 +25,7 @@
        <div class="mt10 table fs-14 break">
            <div class="kitbox row tc fs-14">
                <div class=" ">图片</div>
                <div class="box-flex-1">商品名/条码</div>
                <div class="box-flex-1">药品名/条码</div>
                <div class=" ">数量</div>
            </div>
            <div class="kitbox row tc ptb10">
@ -47,9 +47,9 @@
                    </div>
                </div>
                <div class="box-flex-1 ">
                    <div class="lh30 ellipsis">商品名/条码商品名/条码商品名/条码</div>
                    <div class="lh30 ellipsis">药品名/条码药品名/条码药品名/条码</div>
                    <div><van-icon name="arrow-down" /></div>
                    <div class="lh30 ellipsis">商品名/条码商品名/条码商品名/条码</div>
                    <div class="lh30 ellipsis">药品名/条码药品名/条码药品名/条码</div>
                </div>
                <div class=" ">
                    <div class="lh30">2</div>

+ 61 - 49
mini-pro-web/src/views/replenishment/record/list.vue

@ -10,19 +10,42 @@
        </van-sticky>
        <CustomList
			ref="customList"
            :searchfun='false'
            searchPlaceholder="输入药品名称搜索"
			@onLoad="onLoad">
            <div class="list">
                <van-collapse v-model="activeName" accordion>
                <div class="item" v-for="(citem, k) in list" :key="k">
                    <template>
                        <div>操作时间:{{citem.createTime}}</div>
                        <div>操作货道:{{citem.layerNo}}层{{citem.mergeCargo}}列</div>
                        <div v-if="active==0">补货药品:{{citem.drugName}}</div>
                        <div v-if="active==2">上架药品:{{citem.drugName}}</div>
                        <div v-else-if="active==3">下架药品:{{citem.drugName}}</div>
                        <div v-if="citem.quantity >= citem.oldQuantity">变动数:{{citem.quantity - citem.oldQuantity}}</div>
                        <div v-else>变动数:{{citem.quantity}}</div>
                        <div>操作人员:{{citem.name}}</div>
                    </template>
                    <!-- <template>
                        <div>换货时间:2020-08-24 17:15:19</div>
                        <div>设备编号:149122021070000</div>
                        <div>换货人员:张三</div>
                    </template>
                    <template>
                        <div>上货时间:2020-08-24 17:15:19</div>
                        <div>设备编号:149122021070000</div>
                        <div>上货人员:张三</div>
                    </template> -->
                </div>
                <!-- <van-collapse v-model="activeName" accordion>
                    <van-collapse-item v-for="(item, i) in list" :key="i" :title="item.equName" :name="i">
                        <div class="item" v-for="(citem, k) in item.children" :key="k">
                            <template>
                                <div>补货时间:{{citem.createTime}}</div>
                                <div>操作时间:{{citem.createTime}}</div>
                                <div>设备编号:{{citem.equNum}}</div>
                                <div>商品数量:{{citem.quantity}}</div>
                                <div>补货人员:{{citem.createUserName}}</div>
                                <div>药品数量:{{citem.quantity}}</div>
                                <div>操作人员:{{citem.createUserName}}</div>
                            </template>
                            <!-- <template>
                            <template>
                                <div>换货时间:2020-08-24 17:15:19</div>
                                <div>设备编号:149122021070000</div>
                                <div>换货人员:张三</div>
@ -31,10 +54,10 @@
                                <div>上货时间:2020-08-24 17:15:19</div>
                                <div>设备编号:149122021070000</div>
                                <div>上货人员:张三</div>
                            </template> -->
                            </template>
                        </div>
                    </van-collapse-item>
                </van-collapse>
                </van-collapse> -->
            </div>
        </CustomList>
    </div>
@ -45,6 +68,7 @@ export default{
    name: 'replenishmentRecordList',
    data(){
        return {
            deviceId: this.$route.query.deviceId,
            active: 0,
            activeName: '',
            list: [],
@ -60,18 +84,19 @@ export default{
    },
    methods:{
        onLoad({page, pageSize, searchText}){
            var that = this, 
                params = {
                    type: this.active+1,
                    userId: this.user.id,
                    page: page,
                    size: pageSize
                };
            console.log('getDeviceInventoryRecordListWithUserId', params)
            var params = {
                deviceId: this.deviceId,
                type: this.active+1,
                userId: this.user.id,
                drugName: searchText,
                page: page,
                size: pageSize
            };
            console.log('getDeviceInventoryRecordListByDeviceId', params)
            medicineAbinetApi
                .getDeviceInventoryRecordListWithUserId(params)
                .getDeviceInventoryRecordListByDeviceId(params)
                .then(res=>{
                    console.log('getDeviceInventoryRecordListWithUserId', res)
                    console.log('getDeviceInventoryRecordListByDeviceId', res)
                   if(res.status == 200){
                        var list = res.detailModelList
                        this.list = page==1? list : this.list.concat(list)
@ -85,35 +110,6 @@ export default{
                    this.$refs.customList[this.active].endLoad(false, true)
                })
        },
        // onLoad({page, pageSize, searchText}){
        //     var p = {
        //         userId: this.user.id,
        //         page: 1,
        //         size: pageSize
        //     }
        //     console.log('params', p)
        //     medicineAbinetApi.getDeviceListWithUserId(p)
        //         .then(res=>{
        //             console.log('getDeviceListWithUserId', res)
        //             if(res.status == 200){
        //                 res.detailModelList.forEach(el=>{
        //                     el.children = []
        //                 })
        //                 var list = res.detailModelList
                        
        //                 this.list = page==1? list : this.list.concat(list)
        //                 debugger
        //                 this.$refs.customList.endLoad(res.totalPage<=page, this.list.length)
        //             } else {
        //                 this.list = []
        //                 this.$refs.customList.endLoad(false, true)
        //             }
        //         }).catch(err=>{
        //             console.error(err)
        //             this.list = []
        //             this.$refs.customList.endLoad(false, true)
        //         })
        // },
    },
}
</script>
@ -128,12 +124,28 @@ export default{
            transform: scaleY(1);
        }
        .item{
            padding: 10px 0;
            padding: 10px 15px;
            border-bottom: 1px solid #e1e1e1;
            background: #fff;
            font-size: 14px;
            color: #333;
            // margin-bottom: 10px;
            &:last-child{
                border-bottom: 0 ;
            }
        }
    }   
}
</style>
</style>
<style lang="scss">
.mainNobotHasTop{
    .replenishment-record-list{
        .custom-list {
            height: calc(100vh - 96px);
            .search{
                top: 96px;
            }
        }
    }
}
</style>

+ 13 - 5
mini-pro-web/src/views/replenishment/start/components/SetStockDialog.vue

@ -4,10 +4,10 @@
            <div class="plr15 ptb10 c-pr" style="width: 80vw">
                <div class="close fs-20"><van-icon @click="emitValue(false)" name="close" /></div>
                <div class="tc fs-14 c-333">
                    <span>{{bussiness==1? '修改容量' : bussiness==2? '矫正库存' : bussiness==4||bussiness==5? '设置库存' : ''}}</span>
                    <span>{{bussiness==1? '修改容量' : bussiness==2? '矫正库存' : bussiness==4||bussiness==5? '设置库存' : bussiness==6? '新增' : ''}}</span>
                </div>
                <template v-if="bussiness==1||bussiness==4||bussiness==5">
                    <div class="tc pt30 pb20"><van-stepper v-model="stock" min="1" /></div>
                <template v-if="bussiness==1||bussiness==4||bussiness==5||bussiness==6">
                    <div class="tc pt30 pb20"><van-stepper v-model="stock" min="1" max="99" button-size="36px" input-width="60px"/></div>
                </template>
                <div class="tc" v-else>
                    <div class="pt10">
@ -19,7 +19,15 @@
                    <div class="pt10 c-333 fs-16">{{data.drugName}}</div>
                    <div class="pt10 c-999">软件显示库存:{{data.qty}}</div>
                    <div class="pt10 pb20 ipt plr50">
                        <van-field v-model="stock" label="" type="digit" placeholder=" 请填写实际库存" />
                        <div class="tc  ">
                            <van-stepper 
                                placeholder="实际库存"
                                v-model="stock" 
                                min="1" 
                                max="99" 
                                button-size="36px" 
                                input-width="60px"/>
                            </div>
                    </div>
                </div>
                <div class="ptb10">
@ -35,7 +43,7 @@ export default{
    props:{
        value: {},
        bussiness: {
            default: 1 //1修改容量 2矫正库存 4设置库存 5选择商品后 设置库存
            default: 1 //1修改容量 2矫正库存 4设置库存 5选择药品后 设置库存  6备药时选择药品
        },
        data: {
            default: function(){

+ 573 - 38
mini-pro-web/src/views/replenishment/start/deviceDetail.vue

@ -1,16 +1,16 @@
<template>
    <div class='replenishment-start-device-detail fs-14'>
        <van-sticky :offset-top="offsetTop">
            <div class="bgc-17b3ec c-fff">
    <div class='replenishment-start-device-detail fs-14' :class="{'is-view': isView}">
        <!-- <van-sticky v-if="!isView" :offset-top="offsetTop"> -->
            <div v-if="!isView" class="bgc-17b3ec c-fff">
                <div class="pt10 plr15 ellipsis_1">当前货柜:{{deviceInfo.device.equName}}</div>
                <van-row>
                    <van-col span="6">
                    <van-col span="8">
                        <div class="tc pt10 pb10">
                            <div class="fs-20">{{deviceInfo.deviceCapacity||0}}</div>
                            <div class="fs-12 pt5">设备容量</div>
                        </div>
                    </van-col>
                    <van-col span="6">
                    <van-col span="8">
                        <div class="tc pt10 pb10">
                            <div class="fs-20">
                                <span>{{deviceInfo.inStock||0}}</span>
@ -19,16 +19,10 @@
                            <div class="fs-12 pt5">在架库存</div>
                        </div>
                    </van-col>
                    <van-col span="6">
                    <van-col span="8">
                        <div class="tc pt10 pb10">
                            <div class="fs-20">{{deviceInfo.outOfStock||0}}</div>
                            <div class="fs-12 pt5">缺货库存</div>
                        </div>
                    </van-col>
                    <van-col span="6">
                        <div class="tc pt10 pb10">
                            <div class="fs-20">{{deviceInfo.earlyWarningCargo||0}}</div>
                            <div class="fs-12 pt5">预警货道</div>
                            <div class="fs-12 pt5">缺药库存</div>
                        </div>
                    </van-col>
                </van-row>
@ -39,26 +33,86 @@
                    <div class="box-flex-1 ml5">关闭:{{deviceInfo.closedCargo || 0}}</div>
                </div>
            </div>
        </van-sticky>
        <div class="fs-14 pl15 ptb10 bgc-fff">
            <span>从上往下数</span>
            <div class="color-block"></div>
            <span class="ml5 fs-12">已关闭</span>
            <div class="color-block ml10 red"></div>
            <span class="ml5 fs-12">故障</span>
        <!-- </van-sticky> -->
        <div class="fs-14 pl15 ptb10 bgc-fff kitbox">
            <div class="box-flex-1 lh24">
                <span>从上往下数</span>
                <div class="color-block"></div>
                <span class="ml5 fs-12">已关闭</span>
                <div class="color-block ml10 red"></div>
                <span class="ml5 fs-12">故障</span>
            </div>
            <div class="plr15" v-if="!isView&&this.outDetailList&&this.outDetailList.length&&$hasAuth('device', 'operate','replenish')">
                <van-button v-if="curOrder" @click="updateStockUpStatus(curOrder, 2)" type="primary" color="#17b3ec" size="mini">完成入库</van-button>
                <van-button v-else-if="orderList&&orderList.length" @click="showOrderPicker=true" type="primary" color="#17b3ec" size="mini">导入申领药品单</van-button>
            </div>
            <div class="plr15" v-if="isView&&$hasAuth('device', 'operate','replenish')">
                <van-button @click="gotoUrl('/replenishment/start/deviceDetail', {deviceId: deviceId})" type="primary" color="#17b3ec" size="mini">点击进行入库</van-button>
            </div>
        </div>
        <div class="kitbox">
        <div class=" list-panel">
            <div class="kitbox">
            <div class="left-list">
                <van-sidebar v-model="activeKey">
                    <van-sidebar-item v-for="(item, i) in list" :key="i" :title="(i+1)+'层'"  />
                    <van-sidebar-item v-for="(item, i) in list" :key="i" :title="i==0? '药品库' : (i)+'层'"  />
                </van-sidebar>
            </div>
            <div class="list box-flex-1 bgc-fff">
                <div class="item" v-for="(item, k) in curItem.list" :key="k">
                    <ProductItem :data="item" :index="k"/>
                <div v-if="activeKey===0" class="plr10">
                    <div @click="toQuick(item)" class="drug-item kitbox" v-for="(item, k) in curItem.list" :key="k">
                        <div class="sort" v-if="!curOrder" ><div>{{k+1}}</div></div>
                        <div class="photo">
                            <img src="@/assets/images/drug_default.png" alt="">
                        </div>
                        <div class="box-flex-1 pl10">
                            <div class="fs-15 ellipsis_1 c-333">{{item.drugName}}</div>
                            <div class="fs-14 c-666">
                                <div>编码:{{item.drugCode}}</div>
                                <div>规格:{{item.specif}}</div>
                                <div>当前库存量:{{item.qty||item.inventoryNum||Number(item.total||0)}}</div>
                                <div v-if="curOrder">未放置数量:{{accessLeftNum(item)}}</div>
                            </div>
                        </div>
                    </div>
                </div>
                <template v-else>
                    <template v-for="(item, k) in curItem.list">
                        <div class="item" v-if="item.state!=20" :key="k">
                            <ProductItem :bussuness="bussuness" @onChange="onChange($event, item)" :data="item" :index="k" :isView="isView"/>
                        </div>
                    </template>
                </template>
            </div>
            </div>
        </div>
        
        <div class="bot-banner">
            <div class="kitbox">
                <div v-if="!isManage" class="box-flex-1 plr5"><van-button @click="changeManage" block plain color="#17b3ec"  type="primary" round>货道管理</van-button></div>
                <template v-else>
                    <div class="box-flex-1 plr5"><van-button @click="openAndCloseCargo" block plain color="#17b3ec"  type="primary" round>关闭/开启货道</van-button></div>
                    <div class="box-flex-1 plr5"><van-button @click="mergeAndSplitCargo" block plain color="#17b3ec"  type="primary" round>合并/拆分货道</van-button></div>
                    <div class="plr5"><van-button @click="changeManage" class="w50" block plain color="red"  round type="primary" >取消</van-button></div>
                </template>
            </div>
        </div>
        <van-popup v-model="showOrderPicker">
            <div class="tc fs-16 pt15 pb10">药品申领单选择</div>
            <div class="order-list" v-if="orderList&&orderList.length">
                <div class="order-item kitbox ptb10" v-for="item in orderList" :key="item.id">
                    <div class="box-flex-1">
                        <div class="break-all">药品申领单号:{{item.docNum}}</div>
                        <div class="break-all">新增日期:{{item.docTime}}</div>
                        <div class="break-all">申领品类:{{item.replenishCate}}</div>
                        <div class="break-all">申请数量:{{item.replenishInventory}}</div>
                    </div>
                    <div class="pl15 box-v-middle">
                        <van-button @click="updateStockUpStatus(item, 1)" size="mini" type="info">导入</van-button>
                    </div>
                </div>
            </div>
        </van-popup>
    </div>
</template>
<script>
@ -69,16 +123,30 @@ export default{
    components: {
        ProductItem
    },
    props: ['isView'],
    data(){
        return {
            deviceInfo: {device: ''},
            deviceId: this.$route.query.deviceId,
            list: [],
            list: [{
                index: -1,
                list: []
            }],
            activeKey: 0,
            curItem: [],
            openCount: 0,
            closeCount: 0,
            faultCount: 0
            faultCount: 0,
            outDetailList: [],
            deviceDrugList: [],
            showDeviceDrug: true,
            curOrder: '',
            orderList: [],
            showOrderPicker: false,
            selItemList: [],
            isManage: false,
            bussuness: ''
        }
    },
    watch:{
@ -87,15 +155,166 @@ export default{
        }
    },
    created() {
        this.findMediicinecabinetInventoryByDeviceId()
        this.initPage()
        this.findDeviceById()
    },
    methods:{
        $refreshData(){
            this.findMediicinecabinetInventoryByDeviceId()
            this.getDrugInventoryCount()
            if(this.curOrder){
                this.queryUpListByDeviceIdAndStatus()
            }
        },
        findMediicinecabinetInventoryByDeviceId(){
        async initPage(){
            this.$loading('加载中..')
            await this.queryUpListByDeviceIdAndStatus()
            await this.queryUpListByStatus()
            await this.getDrugInventoryCount()
            await this.getOutDetailByUserIdAndDeviceId()
            this.findMediicinecabinetInventoryByDeviceId()
        },
        checkUpdateStockUpStatus(item, status){
            return new Promise((resolve, reject)=>{
                if(status == 2){
                    this.$dialog.confirm({
                        title: '完成入库',
                        confirmButtonText: "完成入库",
                        message: `请确认药品申领单:${item.docNum} 是否全部完成药品入库,完成后生效并删除此药品申领单`,
                    })
                    .then(() => {
                        resolve(true)
                    })
                    .catch(()=>{
                        resolve(false)
                    })
                } else {
                    resolve(true)
                }
            })
        },
        updateStockUpStatus(item, status){
            this.checkUpdateStockUpStatus(item, status).then(res=>{
                if(!res){
                    return
                }
                this.$toast('加载中..')
                //查备药单详情
                let p = {
                    equNum: this.deviceInfo.device.equNum,
                    id: item.outId || item.id,
                    status
                }
                console.log('updateStockUpStatus', p)
                medicineAbinetApi
                    .updateStockUpStatus(p)
                    .then(res=>{
                        this.$toast.clear()
                        console.log('updateStockUpStatus', res)
                        if(res && res.status == 200){
                            if(status == 1){
                                this.showOrderPicker = false
                                var mediicinestockout = res.obj.mediicinestockout
                                mediicinestockout.outId = res.obj.id
                                this.curOrder = mediicinestockout
                                this.list[0].list = _.filter(this.curOrder.mediicinestockoutdetails, v=>{
                                    return this.accessLeftNum(v)>0
                                })
                            } else {
                                this.curOrder = ''
                                this.list[0].list = this.deviceDrugList
                            }
                            this.queryUpListByStatus()
                        }
                    })
                    .catch(err=>{
                        console.error(err)
                    })
            })
        },
        async queryUpListByStatus(){
            //查询已领取 未导入的备药单
            let p = {
                replenishEr: this.user.id,
                deviceId: this.deviceId
            }
            console.log('queryUpListByStatus', p)
            await medicineAbinetApi
                .queryUpListByStatus(p)
                .then(res=>{
                    console.log('queryUpListByStatus', res)
                    this.orderList = res.detailModelList
                })
                .catch(err=>{
                    console.error(err)
                })
        },
        async queryUpListByDeviceIdAndStatus(){
            //查询是否存在未完成备药单
            let p = {
                replenishEr: this.user.id,
                deviceId: this.deviceId
            }
            console.log('queryUpListByDeviceIdAndStatus', p)
            await medicineAbinetApi
                .queryUpListByDeviceIdAndStatus(p)
                .then(res=>{
                    console.log('queryUpListByDeviceIdAndStatus', res)
                    if(res && res.detailModelList && res.detailModelList.length){
                        var mediicinestockout = res.detailModelList[0].mediicinestockout
                        mediicinestockout.outId = res.detailModelList[0].id
                        this.curOrder = mediicinestockout
                        this.list[0].list = _.filter(this.curOrder.mediicinestockoutdetails, v=>{
                            return this.accessLeftNum(v)>0
                        })
                    }
                })
                .catch(err=>{
                    console.error(err)
                })
        },
        async getDrugInventoryCount(){
            let p = {
                deviceId: this.deviceId
            }
            console.log('getDrugInventoryCount', p)
            await medicineAbinetApi
                .getDrugInventoryCount(p)
                .then(res=>{
                    console.log('getDrugInventoryCount', res)
                    if(!this.curOrder){
                        this.list[0].list = res.detailModelList
                    }
                    this.deviceDrugList = res.detailModelList
                })
                .catch(err=>{
                    console.error(err)
                })
        },
        async getOutDetailByUserIdAndDeviceId(){
            let p = {
                deviceId: this.deviceId,
                userId: this.user.id
            }
            console.log('getOutDetailByUserIdAndDeviceId', p)
            await medicineAbinetApi
                .getOutDetailByUserIdAndDeviceId(p)
                .then(res=>{
                    console.log('getOutDetailByUserIdAndDeviceId', res)
                    res.detailModelList.forEach(v=>{
                        var exist = _.find(this.deviceDrugList, m=>{
                            return v.drugCode == m.drugCode
                        })
                        v.qty = (exist&&exist.qty) || 0
                    })
                    this.outDetailList = res.detailModelList
                })
                .catch(err=>{
                    console.error(err)
                })
        },
        findMediicinecabinetInventoryByDeviceId(){
            this.list.splice(1, this.list.length)
            let p = {
                deviceId: this.deviceId
            }
@ -110,6 +329,9 @@ export default{
                        var list = _.map(res.detailModelList, v=>{
                            var key = _.keys(v)[0]
                            v[key].forEach(m => {
                                m.layerNo = Number(m.layerNo)
                                m.wayerNo = Number(m.wayerNo)
                                m.isActive = false
                                m.cargoState==1? openCount++ : closeCount++
                                if(m.faultState==1){
                                    faultCount++
@ -124,7 +346,7 @@ export default{
                        this.closeCount = closeCount
                        this.faultCount = faultCount
                        list = _.sortBy(list, 'index')
                        this.list = list
                        this.list = this.list.concat(list)
                        this.curItem = this.list[this.activeKey]
                        console.log(list, this.curItem)
                    }
@ -149,30 +371,293 @@ export default{
                    console.error(err)
                })
        },
        changeShowDrug(){
            this.showDeviceDrug = !this.showDeviceDrug
            this.list[0].list = this.showDeviceDrug? this.deviceDrugList : this.outDetailList
        },
        toQuick(item){
            if(this.isView){
                return
            }
            console.log(item)
            this.gotoUrl('/replenishment/start/quick', {
                deviceId: this.deviceId,
                drugName: item.drugName,
                drugCode: item.drugCode,
                drugId: item.drugId,
                qty: item.qty||item.inventoryNum||Number(item.total||0),
                quantity: this.accessLeftNum(item),  
                outDetailId: item.id,
                specif: encodeURIComponent(item.specif)
            })
        },
        accessLeftNum(item){
            var left = (item.quantity||0) - (item.batchNum||0)
            return left<0? 0 : left
        },
        changeManage(){
            if(this.isManage){
                this.selItemList.forEach(v=>{
                    v.isActive = false
                })
                this.selItemList = []
                this.bussuness = '';
            } else{
                this.bussuness = 'quick';
            }
            this.isManage = !this.isManage
        },
        onChange(isActive, item){
            item.isActive = isActive
            if(isActive){
                this.selItemList.push(item)
            } else {
                this.selItemList.splice(this.selItemList.indexOf(item), 1)
            }
        },
        checkOpenOrClose(){
            return new Promise((resolve, reject)=>{
                var g = _.groupBy(this.selItemList, 'cargoState')
                if(g[1] && g[0]){
                    this.$dialog.confirm({
                        title: '货道设置',
                        message: `选中货道已包含"关闭"和"开启"货道,请选择`,
                        confirmButtonText: '全部开启',
                        cancelButtonText: '全部关闭'
                    })
                    .then(() => {
                        resolve(1)
                    })
                    .catch(()=>{
                        resolve(0)
                    })
                } else {
                    resolve(g[1]? 0 : 1)
                }
            })
        },
        openAndCloseCargo(){
            if(!this.selItemList || !this.selItemList.length){
                this.$toast('请选择要操作的货道')
                return
            }
            this.checkOpenOrClose().then(cargoState=>{
                this.$nextTick(()=>{
                    this.$loading('保存中..')
                    var ids = []
                    this.selItemList.forEach(v=>{
                        if(v.state == 21){
                            var cargoIds = v.merge.split(',')
                            cargoIds.forEach(m => {
                                ids.push(this.list[Number(v.layerNo)].list[Number(m)-1].id)
                            })
                        } else {
                            ids.push(v.id)
                        }
                    })
                    console.log('ids', ids)
                    let p = {
                        cargoIds: ids.join(','),//必穿		货道id,多个id,英文逗号隔开,例如   1,2 		4,5,6
                        cargoState 		//必传		1开启,0关闭
                    }
                    console.log('params', p)
                    medicineAbinetApi
                        .openAndCloseCargo(p)
                        .then(res=>{
                            console.log('openAndCloseCargo', res)
                            this.selItemList.forEach(v=>{
                                v.isActive = false
                                v.cargoState = cargoState
                            })
                            this.selItemList = []
                            this.$toast({
                                message: '操作成功',
                                forbidClick: true,
                                onClose: ()=>{
                                }
                            })
                            this.findDeviceById()
                            this.setBackRefresh(true)
                        })
                        .catch(err=>{
                            console.error(err)
                        })
                })
            })
        },
        checkMerge(){
            return new Promise((resolve, reject)=>{
                var exist = _.find(this.selItemList, v=>{
                    return !!v.drugCode
                })
                if(exist){
                    this.$toast.clear()
                    this.$dialog.confirm({
                        message: '当前合并货道存在药品,需把药品下架并取出,如您继续合并默认下架全部药品',
                        confirmButtonText: '继续合并'
                    })
                    .then(() => {
                        this.$loading('保存中..')
                        resolve(true)
                    })
                    .catch(() => {
                        resolve(false)
                    });
                    return 
                }
                resolve(true)
            })
        },
        checkSplit(){
            return new Promise((resolve, reject)=>{
                this.$toast.clear()
                this.$dialog.confirm({
                    message: '货道拆分后请取下货道上的药品',
                    confirmButtonText: '继续拆分'
                })
                .then(() => {
                    resolve(true)
                })
                .catch(() => {
                    resolve(false)
                });
            })
        },
        async mergeAndSplitCargo(){
            this.$loading('保存中..')
            var ids = []
            var g = _.groupBy(this.selItemList, 'state')
            if((g['21'] || g['20']) && g['1']){
                this.$toast.clear()
                this.$dialog.alert({
                    title: '货道设置',
                    message: `当前选中货道包含合并,您需要先手动拆分合并的货道`,
                    confirmButtonText: '我已知悉',
                })
                return
            }
            var isMerge = g['21']? false : true
            if(isMerge){
                if(!this.selItemList.length || this.selItemList.length<2){
                    this.$toast('至少选择两个相邻的货道')
                    return
                }
                var list = _.sortBy(this.selItemList, ['layerNo', 'wayerNo'])
                var exist = _.find(list, (v, i)=>{
                    var next = list[i+1]
                    if(next){
                        if(next && v.layerNo!=next.layerNo){
                            return true
                        }
                        if(Number(v.wayerNo)+1 != Number(next.wayerNo)){
                            return true
                        }
                    }
                    return false
                })
                console.log(this.selItemList, 'this.selectList')
                if(exist){
                    this.$toast('只能选择相邻的货道进行合并')
                    return 
                }
                if(!await this.checkMerge()){
                    return
                }
                ids = _.map(list, v=>{
                    return v.id
                })
            } else {
                if(!this.selItemList.length || this.selItemList.length>1 || this.selItemList[0].state!=21){
                    this.$toast('请选择一个主货道')
                    return
                }
                if(!await this.checkSplit()){
                    return
                }
                this.$loading('保存中..')
                var item = this.selItemList[0]
                ids.push(item.id)
            }
            
            var p = {
                userId: this.user.id,
                cargoIds: ids.join(','),
                isMerge
            }
            console.log(p)
            medicineAbinetApi
                .mergeAndSplitCargo(p)
                .then(res=>{
                    console.log('mergeAndSplitCargo', res)
                    if(res.status == 200){
                        this.selItemList = []
                        this.$toast('操作成功')
                        this.findDeviceById()
                        this.$refreshData()
                    } 
                })
                .catch(err=>{
                    console.error(err)
                })
        },
    },
}
</script>
<style lang='scss' scoped>
.replenishment-start-device-detail{
    .van-sidebar{
        // width: 56px;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    height: 100vh;
    .list-panel{
        -webkit-box-flex: 1;
        position: relative;
        >.kitbox{
            height: 100%;
            width: 100%;
            position: absolute;
        }
    }
    .list{
        display: flex;
        flex-wrap: wrap;
        height: calc(100vh - 153px);
        overflow-y: auto;
        // min-height: calc(100vh - 130px);
        align-content: flex-start;
        .item{
            margin-left: 5px;
            margin-bottom: 5px;
            height: 80px;
            .components-product-item{
                width: 90px;
            }
        }
        .drug-item{
            margin-top: 10px;
            img{
                width: 60px;
                border-radius: 5px;
            }
            .sort{
                display: -webkit-box;
                padding-right: 10px;
                padding-top: 20px;
                >div{
                    font-size: 14px;
                    line-height: 20px;
                    width: 20px;
                    height: 20px;
                    background: #17b3ec;
                    border-radius: 50%;
                    color: #fff;
                    text-align: center
                }
            }
        }
    }
    .left-list{
        height: calc(100vh - 153px);
    .left-list, .list{
        height: 100%;
        overflow-y: auto;
    }
    .color-block{
        background: #ff9526;
@ -185,14 +670,64 @@ export default{
            background: #ff5e6c;
        }
    }
    &.is-view{
        .bot-banner{
            display: none;
        }
    }
    .van-popup{
        border-radius: 10px;
    }
    .order-list{
        max-height: 50vh;
        overflow-y: auto;
        padding: 0 15px;
        width: 80vw;
        .order-item{
            border-bottom: 1px solid #e1e1e1;
            &:last-child{
                border-bottom: 0;
            }
        }
    }
    .bot-banner{
        padding: 10px 5px;
        position: relative;
        bottom: 0;
        width: 100%;
        left: 0;
        background: #fff;
        z-index: 3;
        >div{
            -webkit-box-flex: 1;
            .van-button{
                padding: 0;
                font-size: 13px;
                height: 36px;
            }
        }
    }
}
</style>
<style lang="scss">
.mainNobotHasTop{
    .replenishment-start-device-detail{
        .list, .left-list{
            height: calc(100vh - 199px);
        height: calc(100vh - 46px);
    }
}
@supports(bottom: env(safe-area-inset-bottom)){
    .replenishment-start-device-detail{
        .bot-banner{
            &::after{
                content: "";
                height: env(safe-area-inset-bottom);
                width: 100%;
                display: block;
            }
        }
    }
}

+ 1 - 1
mini-pro-web/src/views/replenishment/start/deviceList.vue

@ -2,7 +2,7 @@
<div class='replenishment-start-device-list'>
    <van-sticky :offset-top="offsetTop">
        <van-tabs v-model="active">
            <van-tab title="缺货设备"></van-tab>
            <van-tab title="缺药设备"></van-tab>
            <van-tab title="全部设备"></van-tab>
        </van-tabs>
    </van-sticky>

+ 44 - 5
mini-pro-web/src/views/replenishment/start/productDetail.vue

@ -7,7 +7,9 @@
            />
        </div>
        <div class="tc c-333 pt20 pb10 plr15 break-all">{{info.drugName}}</div>
        <div class="c-17b3ec tc" @click="gotoUrl('/drugList', {deviceId: info.idDevice})">更换商品</div>
        <div class="tc c-333 pt20 pb10 plr15 break-all">{{info.specif}}</div>
        <div class="c-17b3ec tc"><span @click="gotoUrl('/drugList', {deviceId: info.idDevice})">更换药品</span></div>
        <div class=" tc pt20">
            <span class="mr10">现有数量:{{info.qty}} </span>
            <span class="ml10">货道容量:{{info.cargoCapacity}} </span>
@ -19,10 +21,10 @@
            </div>
        </div>
        <div class="bot-banner  ptb10">
            <div><van-button type="info" @click="bussiness=2;setStockShow=true" round block size="small">矫正库存</van-button></div>
            <div><van-button type="info" @click="bussiness=2;setStockShow=true" round block >矫正库存</van-button></div>
            <div class="kitbox pt10">
                <div class="box-flex-1 pr10"><van-button @click="bussiness=1;setStockShow=true" type="info" round block plain size="small">修改容量</van-button></div>
                <div class="box-flex-1 pl10"><van-button @click="checkRemoveDrug()" type="info" round block plain class="red" size="small">下架商品</van-button></div>
                <div class="box-flex-1 pr10"><van-button @click="bussiness=1;setStockShow=true" type="info" round block plain >修改容量</van-button></div>
                <div class="box-flex-1 pl10"><van-button @click="checkRemoveDrug()" type="info" round block plain class="red" >下架药品</van-button></div>
            </div>
        </div>
        <!-- 修改容量 -->
@ -48,7 +50,10 @@ export default{
            setStockShow: false,
            info: '',
            bussiness: 1, //1修改容量 2矫正库存 3上下架
            drugId: ''
            drugId: '',
            drugName: '',
            drugPrice: '',
            from: this.$route.query.from,
        }
    },
    computed:{
@ -60,6 +65,8 @@ export default{
    created() {
        this.$EventBus.$on('drug-sel', data=>{
            this.drugId = data.id
            this.drugName = data.drugName
            this.drugPrice = data.price
            this.bussiness = 4
            this.setStockShow = true
        })
@ -118,6 +125,13 @@ export default{
                    this.$toast.clear()
                    this.$emitRefreshPage('replenishmentStartDeviceDetail')
                    this.$emitRefreshPage('replenishmentDeviceDetail')
                    if(this.from == 'quick'){
                        this.$emitRefreshPage('replenishmentStartQuick', {
                            data,
                            bussiness: bussiness || this.bussiness
                        })
                    }
                    if(bussiness==3){
                        this.$router.back()
                    } else {
@ -148,6 +162,16 @@ export default{
                    this.$emitRefreshPage('replenishmentStartDeviceDetail')
                    this.$emitRefreshPage('replenishmentDeviceDetail')
                    this.selectMediicinecabineInventoryById()
                    if(this.from == 'quick'){
                        this.$emitRefreshPage('replenishmentStartQuick', {
                            drugId: this.drugId,
                            drugName: this.drugName,
                            drugPrice: this.drugPrice,
                            data,
                            bussiness: 4
                        })
                        history.go(-1)
                    }
                })
                .catch(err=>{
                    console.error(err)
@ -208,6 +232,21 @@ export default{
                border-color: #ff5e6c;
            }
        }
        .van-button{
            padding: 0;
            font-size: 13px;
            height: 36px;
        }
    }
}
</style>
<style lang='scss'>
@supports(bottom: env(safe-area-inset-bottom)){
    .replenishment-start-product-detail{
        .bot-banner{
            bottom: env(safe-area-inset-bottom) !important;
        }
    }
}
</style>

+ 604 - 0
mini-pro-web/src/views/replenishment/start/quick.vue

@ -0,0 +1,604 @@
<template>
    <div class='replenishment-start-quick fs-14'>
        <div class="plr10 bgc-fff ptb10">
            <div class="drug-item kitbox" :key="k">
                <div class="photo">
                    <img src="@/assets/images/drug_default.png" alt="">
                </div>
                <div class="box-flex-1 pl10">
                    <div class="fs-15 ellipsis_1 c-333">{{query.drugName}}</div>
                    <div class="fs-14 c-666 kitbox">
                        <div class="box-flex-1">
                            <div>规格:{{decodeStr(query.specif)}}</div>
                            <div>当前库存量:{{query.qty}}</div>
                            <div v-if="outDetailId">未放置数量:{{query.quantity}}</div>
                        </div>
                        <div class="stepper kitbox">
                            <van-stepper v-model="num" integer min="0" max="99" />
                            <div v-if="repAll" class="text">补满</div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <div class="fs-14 pl15 ptb10 bgc-fff kitbox">
            <div class="box-flex-1 lh24">
                <span>从上往下数</span>
                <div class="color-block"></div>
                <span class="ml5 fs-12">已关闭</span>
                <div class="color-block ml10 red"></div>
                <span class="ml5 fs-12">故障</span>
            </div>
        </div>
        <div class="list-panel">
            <div class="kitbox ">
                <div class="left-list">
                    <van-sidebar v-model="activeKey">
                        <van-sidebar-item v-for="(item, i) in list" :key="i" :title="(i+1)+'层'"  />
                    </van-sidebar>
                </div>
                <div class="list box-flex-1 bgc-fff">
                    <template v-if="curItem">
                        <template v-for="(item, k) in curItem.list">
                            <div class="item" v-if="item.state!=20 && (item.drugCode == query.drugCode || !item.drugCode)" :key="k">
                                <ProductItem v-longpress="()=>{gotoDetail(item)}" bussuness="quick" @onChange="onChange($event, item)" :data="item" :index="k"/>
                            </div>
                        </template>
                        <!-- <div class="item" v-for="(item, k) in curItem.list" :key="k">
                            <ProductItem v-if="item.state!=20" bussuness="quick" @onChange="onChange($event, item)" :data="item" :index="k"/>
                        </div> -->
                    </template>
                </div>
            </div>
        </div>
        <div class="bot-banner">
            <div class="kitbox">
                <div class="box-flex-1 plr5"><van-button @click="openAndCloseCargo" block plain color="#17b3ec"  type="primary" round>关闭/开启货道</van-button></div>
                <div class="box-flex-1 plr5"><van-button @click="mergeAndSplitCargo" block plain color="#17b3ec"  type="primary" round>合并/拆分货道</van-button></div>
                <div class="box-flex-1 plr5"><van-button @click="sumit" block color="#17b3ec"  type="primary"  round>完成补货({{allNum}})</van-button></div>
            </div>
        </div>
    </div>
</template>
<script>
import medicineAbinetApi from '@/api/api-medicineAbinet'
import ProductItem from '@/components/ProductItem'
export default{
    name: 'replenishmentStartQuick',
    components: {
        ProductItem
    },
    data(){
        return {
            num: 0,
            query: this.$route.query,
            selItemList: [],
            allNum: 0,
            curCargo: '',
            deviceId: this.$route.query.deviceId,
            list: [],
            activeKey: 0,
            curItem: [],
            repAll: true,
            outDetailId: this.$route.query.outDetailId || ''
        }
    },
    watch:{
        activeKey(n){
            this.curItem = ''
            this.$nextTick(()=>{
                this.curItem = this.list[n]
            })
        },
        num(n, o){
            this.repAll = false
            this.accessNum()
        }
    },
    created() {
        this.initPage()
    },
    methods:{
        decodeStr(str){
            return (str&&decodeURIComponent(str)) || ""
        },
        $refreshData(p){
            if(p){
                var oQty = this.curCargo.cargoCapacity - this.curCargo.qty
                //1修改容量 2矫正库存 3下架药品  4更换药品
                switch(Number(p.bussiness)){
                    case 1: 
                    case 2: 
                        if(p.bussiness==1){
                            // 1修改容量
                            this.curCargo.cargoCapacity = p.data
                            if(this.curCargo.qty > this.curCargo.cargoCapacity){
                                this.curCargo.qty = this.curCargo.cargoCapacity
                            }
                        } else {
                            // 2矫正库存
                            this.curCargo.qty = p.data
                            if(this.curCargo.qty > this.curCargo.cargoCapacity){
                                this.curCargo.cargoCapacity = this.curCargo.qty
                            }
                        }
                        
                        if(this.curCargo.isActive){
                            this.allNum = this.allNum - oQty + (this.curCargo.cargoCapacity - this.curCargo.qty)
                        }
                        break;
                    case 3: 
                        // 3下架药品 
                        this.curCargo.shelfStatus = 0
                        this.curCargo.qty = 0
                        if(this.curCargo.isActive){
                            this.allNum = this.allNum - oQty + this.curCargo.cargoCapacity
                        }
                        break;
                    case 4: 
                        // 4更换药品
                        this.curItem.list.splice(this.curItem.list.indexOf(this.curCargo), 1)
                        if(this.curCargo.isActive){
                            this.allNum = this.allNum - oQty
                        }
                        break;
                }
            } else {
                this.findMediicinecabinetInventoryByDeviceId()
            }
        },
        initPage(){
            this.findMediicinecabinetInventoryByDeviceId()
        },
        findMediicinecabinetInventoryByDeviceId(){
            this.$loading('加载中..')
            let p = {
                deviceId: this.deviceId
            }
            console.log('params', p)
            medicineAbinetApi
                .findMediicinecabinetInventoryByDeviceId(p)
                .then(res=>{
                    console.log('findMediicinecabinetInventoryByDeviceId', res)
                    this.$toast.clear()
                    if(res.detailModelList && res.detailModelList.length){
                        var list = _.map(res.detailModelList, v=>{
                            var key = _.keys(v)[0]
                            return {
                                index: key,
                                list: _.filter(v[key], m=>{
                                    m.layerNo = Number(m.layerNo)
                                    m.wayerNo = Number(m.wayerNo)
                                    m.isActive = false
                                    return true
                                    return m.drugCode == this.query.drugCode || !m.drugCode
                                }),
                            }
                        })
                        list = _.sortBy(list, 'index')
                        this.list = list
                        this.curItem = this.list[this.activeKey]
                        console.log(list, this.curItem)
                    }
                })
                .catch(err=>{
                    console.error(err)
                })
        },
        onChange(isActive, item){
            var num = this.accessItemNum(item)
            item.isActive = isActive
            if(isActive){
                this.selItemList.push(item)
                this.allNum += num
            } else {
                this.selItemList.splice(this.selItemList.indexOf(item), 1)
                this.allNum -= num
            }
            console.log(this.curItem.list.indexOf(item))
        },
        accessItemNum(item){
            var num = 0
            if(this.repAll){
                num += item.cargoCapacity - item.qty
            } else {
                if(this.num - item.qty > 0){
                    num += (this.num - item.qty)
                }
            }
            return num
        },
        accessNum(){
            var num = 0
            this.selItemList.forEach(v=>{
                num += this.accessItemNum(v)
            })
            this.allNum = num
        },
        sumit(){
            if(!this.selItemList || !this.selItemList.length){
                this.$toast("请选择操作货道")
                return
            }
            if(!this.repAll){
                var exist = _.find(this.selItemList, v=>{
                    return v.qty > this.num
                })
                if(exist){
                    this.$dialog.alert({
                        title: '补货设置',
                        message: `补货数量不能小于当前货道库存,请重新选择数量进行补货`,
                        confirmButtonText: '我已知悉',
                    })
                    return
                }
            }
            if(this.outDetailId && this.query.quantity<this.allNum){
                this.$toast('当前补货数量超过了未放置数量,请重新设置')
                return
            }
            this.$dialog.confirm({
                title: '补货设置',
                message: `确定进行补货?`,
                confirmButtonText: '确定',
            })
            .then(() => {
                var list = _.map(this.selItemList, v=>{
                    return {
                        cargoId: v.id,
                        drugId: this.query.drugId,
                        qty: this.repAll? Number(v.cargoCapacity) : this.num
                    }
                }) 
                this.$nextTick(()=>{
                    this.$loading('保存中..')
                    let p = {
                        list: JSON.stringify({list: list}),
                        userId: this.user.id,
                        outDetailId: this.outDetailId
                    }
                    console.log('params', p)
                    medicineAbinetApi
                        .batchAddInventory(p)
                        .then(res=>{
                            this.query.qty += this.allNum
                            this.query.quantity -= this.allNum
                            if(this.query.quantity<0){
                                this.query.quantity = 0
                            }
                            this.allNum = 0
                            console.log('batchAddInventory', res)
                            this.selItemList.forEach(v=>{
                                v.isActive = false
                            })
                            this.selItemList = []
                            this.$toast({
                                message: '操作成功',
                                forbidClick: true,
                                onClose: ()=>{
                                    
                                }
                            })
                            this.setBackRefresh(true)
                            this.$refreshData()
                        })
                        .catch(err=>{
                            console.error(err)
                        })
                })
            })
            var exist = _.find(this.selItemList, v=>{
                return v.faultState == 1
            })
            // if(exist){
            //     this.$toast('所选货道存在故障货道')
            //     return
            // }
            // batchAddInventory
        },
        checkOpenOrClose(){
            return new Promise((resolve, reject)=>{
                var g = _.groupBy(this.selItemList, 'cargoState')
                if(g[1] && g[0]){
                    this.$dialog.confirm({
                        title: '货道设置',
                        message: `选中货道已包含"关闭"和"开启"货道,请选择`,
                        confirmButtonText: '全部开启',
                        cancelButtonText: '全部关闭'
                    })
                    .then(() => {
                        resolve(1)
                    })
                    .catch(()=>{
                        resolve(0)
                    })
                } else {
                    resolve(g[1]? 0 : 1)
                }
            })
        },
        openAndCloseCargo(){
            if(!this.selItemList || !this.selItemList.length){
                this.$toast('请选择要操作的货道')
                return
            }
            this.checkOpenOrClose().then(cargoState=>{
                this.$nextTick(()=>{
                    this.$loading('保存中..')
                    var ids = []
                    this.selItemList.forEach(v=>{
                        if(v.state == 21){
                            var cargoIds = v.merge.split(',')
                            cargoIds.forEach(m => {
                                ids.push(this.list[Number(v.layerNo)-1].list[Number(m)-1].id)
                            })
                        } else {
                            ids.push(v.id)
                        }
                    })
                    console.log('ids', ids)
                    let p = {
                        cargoIds: ids.join(','),//必穿		货道id,多个id,英文逗号隔开,例如   1,2 		4,5,6
                        cargoState 		//必传		1开启,0关闭
                    }
                    console.log('params', p)
                    medicineAbinetApi
                        .openAndCloseCargo(p)
                        .then(res=>{
                            console.log('openAndCloseCargo', res)
                            this.selItemList.forEach(v=>{
                                v.isActive = false
                                v.cargoState = cargoState
                            })
                            this.selItemList = []
                            this.$toast({
                                message: '操作成功',
                                forbidClick: true,
                                onClose: ()=>{
                                }
                            })
                            this.setBackRefresh(true)
                        })
                        .catch(err=>{
                            console.error(err)
                        })
                })
            })
        },
        checkMerge(){
            return new Promise((resolve, reject)=>{
                var exist = _.find(this.selItemList, v=>{
                    return !!v.drugCode
                })
                if(exist){
                    this.$toast.clear()
                    this.$dialog.confirm({
                        message: '当前合并货道存在药品,需把药品下架并取出,如您继续合并默认下架全部药品',
                        confirmButtonText: '继续合并'
                    })
                    .then(() => {
                        this.$loading('保存中..')
                        resolve(true)
                    })
                    .catch(() => {
                        resolve(false)
                    });
                    return 
                }
                resolve(true)
            })
        },
        checkSplit(){
            return new Promise((resolve, reject)=>{
                this.$toast.clear()
                this.$dialog.confirm({
                    message: '货道拆分后请取下货道上的药品',
                    confirmButtonText: '继续拆分'
                })
                .then(() => {
                    resolve(true)
                })
                .catch(() => {
                    resolve(false)
                });
            })
        },
        async mergeAndSplitCargo(){
            this.$loading('保存中..')
            var ids = []
            var g = _.groupBy(this.selItemList, 'state')
            if((g['21'] || g['20']) && g['1']){
                this.$toast.clear()
                this.$dialog.alert({
                    title: '货道设置',
                    message: `当前选中货道包含合并,您需要先手动拆分合并的货道`,
                    confirmButtonText: '我已知悉',
                })
                return
            }
            var isMerge = g['21']? false : true
            if(isMerge){
                console.log(this.selItemList, 'this.selectList')
                if(!this.selItemList.length || this.selItemList.length<2){
                    this.$toast('至少选择两个相邻的货道')
                    return
                }
                var list = _.sortBy(this.selItemList, ['layerNo', 'wayerNo'])
                var exist = _.find(list, (v, i)=>{
                    var next = list[i+1]
                    if(next){
                        if(next && v.layerNo!=next.layerNo){
                            return true
                        }
                        if(Number(v.wayerNo)+1 != Number(next.wayerNo)){
                            return true
                        }
                    }
                    return false
                })
                if(exist){
                    this.$toast('只能选择相邻的货道进行合并')
                    return 
                }
                if(!await this.checkMerge()){
                    return
                }
                ids = _.map(list, v=>{
                    return v.id
                })
            } else {
                if(!this.selItemList.length || this.selItemList.length>1 || this.selItemList[0].state!=21){
                    this.$toast('请选择一个主货道')
                    return
                }
                if(!await this.checkSplit()){
                    return
                }
                this.$loading('保存中..')
                var item = this.selItemList[0]
                ids.push(item.id)
            }
            
            var p = {
                userId: this.user.id,
                cargoIds: ids.join(','),
                isMerge
            }
            console.log(p)
            medicineAbinetApi
                .mergeAndSplitCargo(p)
                .then(res=>{
                    console.log('mergeAndSplitCargo', res)
                    if(res.status == 200){
                        this.selItemList = []
                        this.$toast('操作成功')
                        this.$refreshData()
                        this.setBackRefresh(true)
                    } 
                })
                .catch(err=>{
                    console.error(err)
                })
        },
        gotoDetail(item){
            if(item.shelfStatus==1){
                this.curCargo = item; 
                this.gotoUrl('./productDetail', {
                    id: item.id,
                    from: 'quick'
                })
            }
        }
    },
}
</script>
<style lang='scss' scoped>
.replenishment-start-quick{
    display: -webkit-box;
    -webkit-box-orient: vertical;
    height: 100vh;
    .list-panel{
        -webkit-box-flex: 1;
        position: relative;
        >.kitbox{
            height: 100%;
            width: 100%;
            position: absolute;
        }
    }
    .drug-item{
        img{
            width: 60px;
            border-radius: 5px;
        }
        .stepper{
            -webkit-box-align: end;
            position: relative;
            .text{
                position: absolute;
                background: #f2f3f5;
                width: 34px;
                text-align: center;
                left: 50%;
                transform: translateX(-50%);
                bottom: 0;
                line-height: 27px;
            }
        }
    }
    .list{
        display: flex;
        flex-wrap: wrap;
        align-content: flex-start;
        .item{
            margin-left: 5px;
            margin-bottom: 5px;
            height: 80px;
            .components-product-item{
                width: 90px;
            }
        }
        
    }
    .left-list, .list{
        height: 100%;
        overflow-y: auto;
    }
    .color-block{
        background: #ff9526;
        width: 10px;
        height: 10px;
        display: inline-block;
        margin-left: 20px;
        border-radius: 2px;
        &.red{
            background: #ff5e6c;
        }
    }
    .bot-banner{
        padding: 10px 5px;
        position: relative;
        bottom: 0;
        width: 100%;
        left: 0;
        background: #fff;
        z-index: 3;
        >div{
            -webkit-box-flex: 1;
            .van-button{
                padding: 0;
                font-size: 13px;
                height: 36px;
            }
        }
    }
}
</style>
<style lang="scss">
.mainNobotHasTop{
    .replenishment-start-quick{
        height: calc(100vh - 46px);
    }
}
@supports(bottom: env(safe-area-inset-bottom)){
    .replenishment-start-quick{
        .bot-banner{
            &::after{
                content: "";
                height: env(safe-area-inset-bottom);
                width: 100%;
                display: block;
            }
        }
    }
}
</style>

+ 3 - 3
mini-pro-web/src/views/replenishment/start/selProduct.vue

@ -4,7 +4,7 @@
            <van-search
                v-model="searchText"
                show-action
                placeholder="请输入商品名称搜索"
                placeholder="请输入药品名称搜索"
                @search="onSearch"
                @cancel="onCancel"
            />
@ -25,7 +25,7 @@
                        <div class="box-flex-1 pl10 right" >
                            <div class="fs-14 c-333">J氯化钠注射液(90mg)</div>
                            <div class="fs-12 c-999">
                                <div>商品条码:12464</div>
                                <div>药品条码:12464</div>
                                <div>价格:¥27.00  <span class="ml5">规格:0.33g*27</span></div>
                            </div>
                        </div>
@ -43,7 +43,7 @@
                    <div class="box-flex-1 pl10 right" >
                        <div class="fs-14 c-333">J氯化钠注射液(90mg)</div>
                        <div class="fs-12 c-999">
                            <div>商品条码:12464</div>
                            <div>药品条码:12464</div>
                            <div>价格:¥27.00  <span class="ml5">规格:0.33g*27</span></div>
                        </div>
                    </div>

+ 218 - 0
mini-pro-web/src/views/replenishment/stockUp/createOut.vue

@ -0,0 +1,218 @@
<template>
    <div class='replenishment-stock-up-detail fs-14'>
        <div class="list bgc-fff mb10 ">
            <van-sticky :offset-top="offsetTop">
                <van-field 
                    v-model="replenisherName"
                    @click="showPicker=true" 
                    label="设备管理员" placeholder="请选择设备管理员" readonly is-link input-align="right"/>
                <div class="row kitbox bgc-fff"  >
                    <div class="box-flex-1 pl10">药品名称</div>
                    <div class="tc">缺药数</div>
                    <div class="tc">操作</div>
                </div>
            </van-sticky>
            <div v-for="(item, i) in list" :key="i" class="row kitbox">
                <div class="box-flex-1 pl10 ellipsis">{{item.drugName}}</div>
                <div class="tc"><van-stepper v-model="item.outofstock" min="1" max="99"/></div>
                <div class="tc c-red"><span @click="del(item, i)">删除</span></div>
            </div>
        </div>
        <div class="btns">
            <div class="pl15 pr8">
                <van-button plain @click="toAdd" block round type="info">选择药品</van-button>
            </div>
            <div class="pl8 pr15">
                <van-button block @click="submit" round type="info">{{createOutAuth? '生成出库并领取' : '生成药品申领单'}}</van-button>
            </div>
        </div>
        <van-popup v-model="showPicker" round position="bottom">
            <van-picker
                show-toolbar
                :columns="replenishErList"
                @cancel="showPicker = false"
                @confirm="onConfirm"
            />
            </van-popup>
    </div>
</template>
<script>
import medicineAbinetApi from '@/api/api-medicineAbinet'
export default{
    name: 'replenishmentStockUpCreateOut',
    data(){
        return {
            upId: this.$route.query.upId,
            deviceId: this.$route.query.deviceId,
            list: [],
            oriData: [],
            replenisherName: "",
            replenisherId: "",
            replenishErList: [],
            showPicker: false,
            delList: []
        }
    },
    computed:{
        createOutAuth(){
            return this.$hasAuth('replenishmentMgnt', 'pickingList','createOut')
        },
    },
    created() {
        this.getUpDetailById()
        this.getUserListByDeviceId()
        this.$EventBus.$on('drug-sel', (item)=>{
            var index = _.findIndex(this.delList, v=>{
                return v.drugCode == item.drugCode
            })
            this.delList.splice(index, 1)
            this.list.push(item)
        })
    },
    methods:{
        getUpDetailById(){
            this.$loading('加载中..')
            let p = {
                idUp: this.upId
            }
            console.log('params', p)
            medicineAbinetApi
                .getUpDetailById(p)
                .then(res=>{
                    this.$toast.clear()
                    console.log('getUpDetailById', res)
                    // this.model = res.obj.info || {}
                    res.obj.list.forEach(v => {
                        if(v.price){
                            v.totalPrice = (Number(v.price) * Number(v.outofstock)).toFixed(2)
                        }
                    });
                    
                    this.list = res.obj.list
                    if(res.obj.info.replenishEr){
                        this.replenisherId = res.obj.info.replenishEr||""
                        this.replenisherName = res.obj.info.replenishErName||""
                    } else if(this.user.curRoleCode == 'replenisher'){
                        this.replenisherName = this.user.name
                        this.replenisherId = this.user.id
                    }
                })
                .catch(err=>{
                    console.error(err)
                })
        },
        submit(){
            if(!this.list.length){
                this.$toast('请选择药品')
                return
            }
            if(this.createOutAuth && !this.replenisherId){
                this.$toast('请选择设备管理员')
                return
            }
            this.$loading('保存中..')
            var drugs = _.map(this.list, v=>{
                    return {
                        "drugId": v.drugId,		//药品id
                        "qty": v.outofstock	
                    }
                })
                var p = {
                    upId: this.upId,
                    remark: "",
                    replenishEr: this.replenisherId,
                    deviceId: this.deviceId,
                    drugs,
                    userId: this.user.id
                }
                console.log('baseOutCreateUp', JSON.stringify(p))
                medicineAbinetApi
                    .baseOutCreateUp({
                        jsonData: JSON.stringify({obj:p}),
                    })
                    .then(res => {
                        this.$toast('生成成功')
                        this.$emitRefreshPage("replenishmentPickingList")
                        history.back()
                    })
                    .catch(err=>{
                        console.error(err)
                    })
        },
        del(item, k){
            this.delList.push(item)
            this.list.splice(k, 1)
        },
        toAdd(){
            this.$store
                .dispatch("SetDrugList", this.delList)
                .then(() => {
                    this.gotoUrl('/replenishment/stockUp/drugList', {})
                });
        },
        onConfirm(value) {
            this.replenisherName = value.text;
            this.replenisherId = value.id;
            this.showPicker = false;
        },
        getUserListByDeviceId(){
            this.$loading('加载中..')
            if(!this.deviceId){
                return
            }
            medicineAbinetApi
                .getUserListByDeviceId({
                    deviceId: this.deviceId
                })
                .then(res => {
                    this.$toast.clear()
                    console.log('getUserListByDeviceId', res)
                    this.replenishErList = _.map(res.detailModelList || [], v=>{
                        return {
                            text: v.name,
                            id: v.id
                        }
                    })
                }).catch(err=>{
                    console.error(err)
                })
        },
    },
}
</script>
<style lang='scss' scoped>
.replenishment-stock-up-detail{
    padding-bottom: 100px;
    .list{
        .van-cell{
            padding-left: 10px;
        }
        .row{
            padding: 10px 0;
            border-bottom: 1px solid #e1e1e1;
            line-height: 28px;
            >div:nth-child(3){
                width: 60px;
            }
            >div:nth-child(2){
                width: 120px;
            }
            &:last-child{
                border-bottom: 0;
            }
        }
    }
    .btns{
        position: fixed;
        width: 100%;
        left: 0;
        bottom: 20px;
        display: -webkit-box;
        >div{
            width: 50%;
        }
    }
}
</style>

+ 164 - 46
mini-pro-web/src/views/replenishment/stockUp/detail.vue

@ -1,32 +1,43 @@
<template>
    <div class='replenishment-stock-up-detail fs-14'>
        <div class="list bgc-fff ">
            <van-sticky :offset-top="offsetTop">
        <div class="list bgc-fff mb10 ">
            <van-sticky v-if="createOutAuth" :offset-top="offsetTop">
                <van-field 
                    v-model="replenisherName"
                    @click="showPicker=true" 
                    label="设备管理员" placeholder="请选择设备管理员" readonly is-link input-align="right"/>
                <div class="row kitbox bgc-fff"  >
                    <div class="box-flex-1 pl10">商品名称</div>
                    <div class="tc">现料数</div>
                    <div class="tc">缺料数</div>
                    <div class="box-flex-1 pl10">药品名称</div>
                    <div class="tc">现药数</div>
                    <div class="tc">缺药数</div>
                    <div class="tc">操作</div>
                </div>
            </van-sticky>
            <div v-for="(item, i) in list" :key="i" class="row kitbox">
                <div class="box-flex-1 pl10 ellipsis">{{item.drugName}}</div>
                <div class="tc">{{item.qty}}</div>
                <div class="tc">{{item.upInventory}}</div>
                <div class="tc"><van-stepper v-model="item.upInventory" min="1" max="99"/></div>
                <div class="tc c-red"><span @click="del(item, i)">删除</span></div>
            </div>
        </div>
        <div class="btns">
            <div class="pl15 pr8">
                <van-button plain @click="toAdd" block round type="info">新增商品</van-button>
                <van-button plain @click="toAdd" block round type="info">新增药品</van-button>
            </div>
            <div class="pl8 pr15">
                <van-button  block @click="submit" round type="info">生成备货单</van-button>
                <van-button block @click="submit" round type="info">{{createOutAuth? '生成出库并领取' : '生成药品申领单'}}</van-button>
            </div>
        </div>
        <!-- <BotFloatButton :fix="true">下一步,生成备货单</BotFloatButton> -->
        <van-popup v-model="showPicker" round position="bottom">
            <van-picker
                show-toolbar
                :columns="replenishErList"
                @cancel="showPicker = false"
                @confirm="onConfirm"
            />
            </van-popup>
    </div>
</template>
<script>
@ -37,60 +48,128 @@ export default{
        return {
            deviceId: this.$route.query.deviceId,
            list: [],
            oriData: []
            oriData: [],
            replenisherName: "",
            replenisherId: "",
            replenishErList: [],
            showPicker: false
        }
    },
    computed:{
        createOutAuth(){
            return this.$hasAuth('replenishmentMgnt', 'pickingList','createOut')
        },
    },
    created() {
        if(this.createOutAuth){
            this.getUserListByDeviceId()
            if(this.user.curRoleCode == 'replenisher'){
                this.replenisherName = this.user.name
                this.replenisherId = this.user.id
            }
        }
        
        this.$EventBus.$on('drug-sel', (item)=>{
            item.qty = 0
            item.upInventory = 5
            var exist = _.find(this.list, v=>{
                return v.drugCode == item.drugCode
            })
            if(exist){
                return
            }
            exist = _.find(this.oriData, v=>{
                return v.drugCode == item.drugCode
            })
            item.qty = exist&&exist.qty || 0
            // item.upInventory = 5
            this.list.push(item)
            console.log('unusedAisles', this.oriData[0].unusedAisles)
        })
        this.getDetialOutOfStock()
        this.getOutOfStockInfoByDeviceWithPage()
    },
    methods:{
        getDetialOutOfStock(){
        getOutOfStockInfoByDeviceWithPage(){
            this.$loading('加载中..')
            let p = {
                ids: this.deviceId
                deviceId: this.deviceId,
                page: 1,
                size: 9999
            }
            console.log('params', p)
            medicineAbinetApi
                .getDetialOutOfStock(p)
                .getOutOfStockInfoByDeviceWithPage(p)
                .then(res=>{
                    console.log('getDetialOutOfStock', res)
                    console.log('getOutOfStockInfoByDeviceWithPage', res)
                    this.$toast.clear()
                    var data = res.detailModelList[0]
                    data.canPickCount = (data.unusedAisles) + (data.children&&data.children.length||0)
                    this.oriData = res.detailModelList
					this.list = res.detailModelList&&res.detailModelList[0].children
                    this.list = res.detailModelList
                    this.oriData = JSON.parse(JSON.stringify(res.detailModelList))
                })
                .catch(err=>{
                    console.error(err)
                })
        },
        baseOutCreateUp(item){
            return new Promise((resolve, reject)=>{
                var drugs = _.map(item.list, v=>{
                    return {
                        "drugId": v.drugId,		//药品id
                        "qty": v.outofstock	
                    }
                })
                var p = {
                    upId: item.info.id,
                    remark: "",
                    replenishEr: this.replenisherId,
                    deviceId: this.deviceId,
                    drugs,
                    userId: this.user.id
                }
                console.log('baseOutCreateUp', JSON.stringify(p))
                medicineAbinetApi
                    .baseOutCreateUp({
                        jsonData: JSON.stringify({obj:p}),
                    })
                    .then(res => {
                        console.log('baseOutCreateUp', res)
                        if(res && res.status==200){
                            var item = JSON.parse(res.message)
                            medicineAbinetApi
                                .changeMoreReceiveState({
                                    outIds: item.out.id,
                                    state: 1
                                })
                                .then(res => {
                                    resolve()
                                })
                                .catch(err=>{
                                    console.error(err)
                                })
                        }
                    })
                    .catch(err=>{
                        console.error(err)
                        reject()
                    })
            })
        },
        submit(){
            if(!this.oriData[0].children.length){
            if(!this.list.length){
                this.$toast('请选择药品')
                return
            }
            if(this.createOutAuth && !this.replenisherId){
                this.$toast('请选择设备管理员')
                return
            }
            this.$loading('保存中..')
            var list = _.map(this.oriData, v=>{
                return {
                    deviceId: v.id,
                    drugs: _.map(v.children, d=>{
            var p = {
                list: [{
                    deviceId: this.deviceId,
                    drugs: _.map(this.list, d=>{
                        return {
                            drugId: d.id,
                            qty: d.upInventory
                        }
                    })
                }
            })
            var p = {
                list
                }]
            }
            console.log('params', p)
            medicineAbinetApi
@ -99,30 +178,62 @@ export default{
                    jsonData: JSON.stringify(p),
                })
                .then(res => {
                    console.log('baseUpCreateUp', res)
                    if(res.status == 200){
                        // this.setBackRefresh()
                        this.$emitRefreshPage('replenishmentStockUpDeviceList')
                        this.$toast('生成成功')
                        if(this.createOutAuth){
                            return this.baseOutCreateUp(JSON.parse(res.message))
                        } else {
                            return Promise.resolve()
                        }
                    }
                })
                .then(res=>{
                    // this.$emitRefreshPage('replenishmentStockUpDeviceList')
                    this.$toast('生成成功')
                    if(this.createOutAuth){
                        history.go(-2)
                    } else{
                        history.back()
                    }
                })
                .catch(err=>{
                    console.error(err)
                })
                
        },
        del(item, k){
            this.list.splice(k, 1)
            console.log('unusedAisles', this.oriData[0].unusedAisles)
        },
        toAdd(){
            var device = this.oriData[0]
            if(device.canPickCount <= this.list.length){
				this.$toast(`已达到药柜容量,无法在添加`)
				return
			}
            this.gotoUrl('/drugList', {deviceId: device.id})
        }
            this.gotoUrl('/drugList', {deviceId: this.deviceId, bussiness: 6})
        },
        onConfirm(value) {
            this.replenisherName = value.text;
            this.replenisherId = value.id;
            this.showPicker = false;
        },
        getUserListByDeviceId(){
            this.$loading('加载中..')
            if(!this.deviceId){
                return
            }
            medicineAbinetApi
                .getUserListByDeviceId({
                    deviceId: this.deviceId
                })
                .then(res => {
                    this.$toast.clear()
                    console.log('getUserListByDeviceId', res)
                    this.replenishErList = _.map(res.detailModelList || [], v=>{
                        return {
                            text: v.name,
                            id: v.id
                        }
                    })
                }).catch(err=>{
                    console.error(err)
                })
        },
    },
}
</script>
@ -130,11 +241,18 @@ export default{
.replenishment-stock-up-detail{
    padding-bottom: 100px;
    .list{
        .van-cell{
            padding-left: 10px;
        }
        .row{
            padding: 10px 0;
            border-bottom: 1px solid #e1e1e1;
            >div:nth-child(2), >div:nth-child(3), >div:nth-child(4){
                width: 80px;
            line-height: 28px;
            >div:nth-child(2), >div:nth-child(4){
                width: 60px;
            }
            >div:nth-child(3){
                width: 120px;
            }
            &:last-child{
                border-bottom: 0;

+ 5 - 5
mini-pro-web/src/views/replenishment/stockUp/deviceList.vue

@ -2,7 +2,7 @@
<div class='replenishment-stock-up-device-list'>
    <van-sticky :offset-top="offsetTop">
        <van-tabs v-model="active">
            <van-tab title="缺货设备"></van-tab>
            <van-tab title="缺药设备"></van-tab>
            <van-tab title="全部设备"></van-tab>
        </van-tabs>
    </van-sticky>
@ -31,11 +31,11 @@
                    </div>
                    <div class="lh20 ptb10 kitbox">
                        <div class="box-flex-1">
                            <div>待补商品数量:{{item.daibushangpinshuliang}}</div>
                            <div>未设商品货道:{{item.weishezhishangpinhuodao}}</div>
                            <div>待入库药品数量:{{item.daibushangpinshuliang}}</div>
                            <div>未设药品货道:{{item.weishezhishangpinhuodao}}</div>
                            <div>设备所属:{{item.community}}</div>
                            <div>设备编号:{{item.equNum}}</div>
                            <div>上次补货时间:{{item.shangyicibuhuoshijian}}</div>
                            <div >设备编号:{{item.equNum}}</div>
                            <!-- <div>上次补货时间:{{item.shangyicibuhuoshijian}}</div> -->
                        </div>
                        <div class="fs-20 c-pr">
                            <van-icon name="arrow" />

+ 56 - 0
mini-pro-web/src/views/replenishment/stockUp/drugList.vue

@ -0,0 +1,56 @@
<template>
    <div class="drug-list">
        <div class="list" v-if="list.length">
            <div 
                v-for="(item, i) in list" :key="i"
                @click="addDrug(item)"
                class="item mb10 bgc-fff btb-e1e1e1 pt10 pb10 plr15">
                <van-row class="lh25 c-333">
                    <span class="fs-17">{{item.drugName}}</span>
                    <span class="fs-14 ml20">药品编码:{{item.drugCode}}</span>
                </van-row>
                <!-- <van-row class="lh25">
                    <van-col span="12" class="c-999">规格:<span class="c-333">{{item.specif}}</span></van-col>
                    <van-col span="12" class="c-999">零售价:<span class="c-333">{{item.price}}</span></van-col>
                </van-row>
                <van-row class="lh25">
                    <van-col span="12" class="c-999">医保支付价:<span class="c-333"></span></van-col>
                    <van-col span="12" class="c-999">医保支付比例:<span class="c-333"></span></van-col>
                </van-row>
                <van-row class="lh25">
                    <van-col span="12" class="c-999">基药:<span class="c-333"></span></van-col>
                    <van-col span="12" class="c-999">药品类别:<span class="c-333"></span></van-col>
                </van-row> -->
                <!-- <div class="c-ff5e6c fs-14 lh25">高危药品:</div> -->
            </div>
        </div>
        <div v-else class="c-999 fs-14 tc pt20">
            <div>暂无数据~~</div>
        </div>
    </div>
</template>
<script>
import medicineAbinetApi from '@/api/api-medicineAbinet'
export default {
    name: "ReplenishmentDrugSel",
    data(){
        return {
            list: []
        }
    },
    async created(){
        this.list = this.$store.state.app.drugList
        console.log(this.list)
    },
    methods: {
        addDrug(item){
            this.$EventBus.$emit('drug-sel', item)
            history.back()
        }
    }
};
</script>
<style lang="scss" scoped>
@import '@/views/drug/css/drugSel.scss';
</style>

+ 1 - 1
mini-pro-web/vue.config.js

@ -7,7 +7,7 @@ function resolve(dir) {
}
module.exports = {
  publicPath: process.env.NODE_ENV==='production'?process.env.VUE_APP_PRE_PATH:"/",
  publicPath: process.env.NODE_ENV==='production'||process.env.NODE_ENV==='test'?process.env.VUE_APP_PRE_PATH:"/",
  outputDir: 'intelligent-medicine-abinet',
  productionSourceMap:false,
  devServer: {