Browse Source

模拟仓库出入库扫描作业

git-svn-id: svn+ssh://10.10.101.21/source/platform/platform-b2b@459 f3bf4e98-0cf0-11e4-a00c-a99a8b9d557d
suntg 11 years ago
parent
commit
e2280e1e46

+ 1 - 0
src/main/webapp/WEB-INF/spring/webmvc.xml

@@ -29,5 +29,6 @@
 
 	<mvc:view-controller path="/" view-name="index" />
 	<mvc:view-controller path="/signin" view-name="signin" />
+	<mvc:view-controller path="/storage" view-name="storage" />
 	<mvc:view-controller path="/signin/register" view-name="register" />
 </beans>

+ 71 - 0
src/main/webapp/WEB-INF/views/mobile/storage.html

@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>优软商务平台</title>
+<meta charset="UTF-8">
+<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+<meta name="viewport"
+	content="initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=0, width=device-width">
+<meta name="baidu-site-verification" content="S0kf5fz0uA" />
+<meta name="keywords"
+	content="优软商务平台,优软B2B平台,商务平台,B2B平台,B2B,电子商务,ERP,UAS,UBTOB.COM,USOFTCHINA.COM,优软">
+<meta name="description" content="优软商务平台,企业供销信息交流平台。">
+<link href="static/img/icon/u.png" rel="icon" type="image/x-icon" />
+<link rel="stylesheet" href="static/lib/bootstrap/css/bootstrap.min.css" />
+<link rel="stylesheet" href="static/lib/fontawesome/css/font-awesome.min.css" />
+<link rel="stylesheet" href="static/lib/angular/toaster.css" />
+<link rel="stylesheet" href="static/css/storage.css" />
+</head>
+<body>
+	<style>
+		body {
+			margin-top: 40px;
+		}
+		.status {
+			position: fixed;
+			top: 0px;
+			left: 0px;
+			width: 100%;
+			height: 40px;
+			line-height: 40px;
+			border-bottom: solid 1px #999999;
+			padding: 5px 10px;
+			font-size: 16px;
+			background: #FFFFFF;
+			z-index: 20;
+		}
+		.checked {
+			width: 60px;
+		}
+	</style>
+
+	<div class="container">
+		<div class="status" ng-controller="StatusCtrl">
+			<div class="left">
+				<i class="fa fa-user"></i> 孙土桂
+			</div>
+			<div class="btn-group right">
+				<label class="btn btn-sm btn-default" ng-class="{'btn-success': status.online, 'checked': status.online}">
+					<input type="radio" class="hidden" name="onlineRadio" ng-model="status.online" ng-value="true"/>
+					<i ng-show="status.online" class="fa fa-wifi"></i> 在线
+				</label>
+				<label class="btn btn-sm btn-default" ng-class="{'btn-warning': !status.online, 'checked': !status.online}">
+					<input type="radio" class="hidden" name="offlineRadio" ng-model="status.online" ng-value="false"/>
+					离线 <i ng-show="!status.online" class="fa fa-warning"></i>
+				</label>
+			</div>
+		</div>
+		<div ui-view></div>
+		<div class="footer text-center f12">
+			
+		</div>
+	</div>
+<!-- 消息提示框  Start-->
+	<toaster-container
+		toaster-options="{'position-class': 'toast-middle-left'}"></toaster-container>
+	<audio src="static/ring/success.wav" id="successRing"></audio>
+	<audio src="static/ring/error.wav" id="errorRing"></audio>
+<script type="text/javascript" src="static/lib/require.js"
+		data-main="static/js/index/mobile.storage.main.js"></script>
+</body>
+</html>

+ 184 - 0
src/main/webapp/resources/css/storage.css

@@ -0,0 +1,184 @@
+body {
+	line-height: 1.6;
+	font-family: "Helvetica Neue", "Hiragino Sans GB", "Microsoft YaHei",
+		"\9ED1\4F53", Arial, sans-serif;
+	color: #222;
+	font-size: 14px;
+}
+
+h1,h2,h3 {
+	font-size: 20px;
+	font-weight: 400;
+	font-style: normal;
+}
+
+a {
+	color: #333;
+	text-decoration: none;
+}
+
+.block {
+	background-color: #fff;
+	width: 100%;
+	position: relative;
+}
+
+.bold {
+	font-weight: bold;
+}
+
+.left {
+	float: left;
+}
+
+.right {
+	float: right;
+}
+
+.f12 {
+	font-size: 12px !important;
+}
+
+.f14 {
+	font-size: 14px !important;
+}
+
+.f16 {
+	font-size: 16px !important;
+}
+
+[ng-click] {
+	cursor: pointer;
+}
+
+.br-r {
+	border-right: 1px solid #e6e6e6;
+}
+
+.br-l {
+	border-left: 1px solid #e6e6e6;
+}
+
+.br-b {
+	border-bottom: 1px solid #e6e6e6;
+}
+
+.padding5 {
+	padding: 0px 5px;
+}
+
+.container {
+	padding-left: 0px;
+	padding-right: 0px;
+}
+
+.ellipsis{
+	width: 80px;
+	overflow:hidden;
+	white-space:nowrap;
+	text-overflow:ellipsis;
+	-o-text-overflow:ellipsis;
+}
+
+@media(min-width: 320px) {
+	.ellipsis{
+		width: 100px;
+	}
+}
+
+@media(min-width: 400px) {
+	.ellipsis{
+		width: 150px;
+	}
+}
+
+@media(min-width: 560px) {
+	.ellipsis{
+		width: 160px;
+	}
+}
+
+.input-sm, .form-group-sm .form-control {
+	padding: 2px 5px;
+	border-radius: 1px;
+}
+
+.btn-sm, .btn-group-sm>.btn {
+	padding: 4px 5px;
+}
+
+.text-num {
+	font-style: normal;
+	font-family: verdana;
+}
+
+.text-muted {
+	color: #888 !important;
+}
+
+.text-inverse {
+	color: #f40 !important;
+}
+
+.text-black {
+	color: #333;
+}
+
+.expand {
+	border-top: solid 2px #339999;
+	border-left: solid 2px #339999;
+	border-right: solid 2px #339999;
+}
+
+.reply {
+	background-color: #339999;
+}
+
+/* top */
+.top {
+	height: 30px;
+	font-family: Microsoft Yahei;
+	border-bottom: solid 1px #999999;
+	line-height: 30px;
+}
+
+.orderInfo {
+	background-color: #339999;
+	color: #FFFFFF;
+	border-bottom: solid 1px #999999;
+	padding-top: 5px;
+	padding-bottom: 5px;
+}
+
+/* footer */
+.footer {
+	padding-top: 5px;
+	background-color: #EEEEEE;
+	border-top: solid 1px #C6C6C6;
+}
+
+/*loading*/
+.loading {
+	display: none;
+	position: absolute;
+	width: 100%;
+	height: 300px;
+	top: 0;
+	left: 0;
+}
+
+.loading.in {
+	display: block;
+}
+
+.loading.in>i {
+	position: absolute;
+	top: 50%;
+	left: 50%;
+	margin: -33px 0 0 -33px;
+	background: url("../img/all/loading.gif") no-repeat center center;
+	width: 66px;
+	height: 66px;
+}
+
+

+ 249 - 0
src/main/webapp/resources/js/index/mobile.storage.app.js

@@ -0,0 +1,249 @@
+define([ 'toaster', 'charts', 'ngTable', 'common/services', 'service/Purc', 'ui.router', 'ui.bootstrap' ], function() {
+	'use strict';
+	var app = angular.module('myApp', ['ngAnimate', 'toaster', 'ui.router', 'common.services', 'PurcServices', 'ui.bootstrap' ]);
+	app.init = function() {
+		angular.bootstrap(document, [ 'myApp' ]);
+	};
+	
+	app.config(function($stateProvider, $urlRouterProvider) {
+		$urlRouterProvider.otherwise('/index');
+		$stateProvider.state('index', {
+			url : "/index",
+			templateUrl : "static/tpl/index_mobile/storage/index.html"
+		}).state('input', {
+			url : "/input",
+			templateUrl : "static/tpl/index_mobile/storage/input.html"
+		}).state('inputOperation', {
+			url: '/input/:code',
+			templateUrl: 'static/tpl/index_mobile/storage/inputOperation.html'
+		}).state('upload', {
+			url: '/upload',
+			templateUrl: 'static/tpl/index_mobile/storage/needToUpload.html'
+		});
+	});
+	
+	app.factory('Symbol', function(){//符号
+		return {
+			currency: function(cur) {//把币别转换成对应的符号
+				if(cur == 'RMB') return '¥';
+				else if(cur == 'USD') return '$';
+				else if(cur == 'EUR') return '€';
+				else return cur;
+			}
+		};
+	}).factory('Ring', function(){//响铃,直接调用
+		return {
+			success: function(){
+				document.getElementById('successRing').play();
+			}, error: function(){
+				document.getElementById('errorRing').play();
+			}
+		}
+	}).factory('Online', function($rootScope){//在线状态,全局获取、设置
+		var status = {online: true};
+		return {
+			setOnline: function(value){
+				status.online = value;
+				$rootScope.$broadcast('online', value);
+			}, getOnline: function(){
+				return status.online;
+			}
+		}
+	});
+	
+	app.controller('IndexCtrl', function($scope, $rootScope){
+		//获取需要上传的数量
+		$scope.getNeedUpCount = function(){
+			var count = 0;
+			angular.forEach($rootScope.orders, function(value,key){
+				angular.forEach(value.orderItems, function(item, key){
+					if(item.replyCount) count += 1;//存在replyCount并且>0就需要上传
+				});
+			});
+			return count;
+		};
+		
+	});
+	
+	app.controller('StatusCtrl', function($scope, $http, Online){
+		$scope.status = {online: true};
+		
+		$scope.$watch('status.online', function(value){//检测用户手动切换在线状态
+			Online.setOnline(value);
+		});
+		
+		$scope.$on('online', function(data){//监听Service中的状态变化
+			$scope.status.online = Online.getOnline();
+		});
+	});
+	
+	app.controller('InputCtrl', function($scope, $http, $rootScope, $location, toaster, PurcOrder, Ring, Online){
+		$scope.orders = $rootScope.orders || [];
+		
+		var contains = function(array, element) {//根据ID判断数组是否包含某个元素
+			var result = false;
+			angular.forEach(array, function(value, key){
+				if(value.id == element.id) {//ID相等即包含
+					result = true; 
+					return result;
+				}
+			});
+			return result;
+		}
+		
+		$scope.getOrder = function(code) {//根据输入的单据id号获取下载单据信息
+			$scope.selectedId = code;
+			console.log('online--' + Online.getOnline());
+			if(contains($scope.orders, {id: code})){//请求的单据id已经被下载在本地了
+				
+			} else {//请求的单据id未被下载在本地了,向服务器发送请求获取数据
+				PurcOrder.get({id: code}, function(data) {//获取成功
+					$scope.getError = false;
+					$scope.orders.push(data);
+					$rootScope.orders = $scope.orders;
+				}, function(response){//获取失败处理
+					$scope.errorCode = code;
+					$scope.getError = true;
+					setTimeout(function(){//2s后取消错误提示,好像没用。。。
+						$scope.getError = false;
+						$scope.errorCode = code;
+					}, 2000);
+				});
+			}
+			Ring.success();//提示成功响铃
+			$scope.batchCode = '';//重置输入框
+		};
+		
+		$scope.search = function($event, batchCode){//enter键触发事件
+			if($event.keyCode == 13) {//Enter事件
+				$scope.getOrder(batchCode);
+			}
+		};
+		
+		$scope.totalQty = function(order) {//获取当前单据还未扫描的物料数量
+			var result = 0;
+			angular.forEach(order.orderItems, function(value, key){
+				result += value.qty - value.replyQty;
+			});
+			return result;
+		};
+		
+		$scope.operate = function(order) {//跳转至对应的单据操作页面
+			$scope.selectedId = order.id;
+			$location.path('input/' + order.id);
+		};
+	});
+	
+	app.controller('InputOperationCtrl', function($scope, $http, $stateParams, $rootScope, toaster, Ring, PurcOrderItem, Online){
+		var getOrder = function(code) {//根据路径中的id号获取对应的单据
+			var result = null;
+			angular.forEach($rootScope.orders, function(value, key){
+				if(value.id == code) {
+					result = value;
+					return result;
+				}
+			});
+			return result;
+		};
+		
+		var containsProduct = function(id) {//判断物料Id是否包含于当前单据
+			var result = null;
+			angular.forEach($scope.order.orderItems, function(value, key){
+				if(value.product.id == id) {
+					result = value;
+					return result;
+				}
+			});
+			return result;
+		};
+		
+		$scope.order = getOrder($stateParams.code);
+		$scope.getOnline = Online.getOnline;
+		
+		$scope.scan = function(id){//扫描事件
+			$scope.noProduct = false;
+			$scope.overError = false;
+			var item = containsProduct(id);
+			if(item){//是当前单据中对应的物料
+				if((item.replyQty||0) < item.qty){
+					Ring.success();
+					$scope.selectedId = item.id;
+					item.replyQty = item.replyQty || 0;
+					item.replyQty += 1;
+					if(Online.getOnline()){//有网络连接
+						//向后台交互
+						PurcOrderItem.reply({orderItemId: item.id}, {delivery: new Date().getTime(), qty: 1, remark: '测试扫描技术'}, 
+						function(data){}, function(response){//请求发生错误
+							if(response.status == 0) {//无网络错误
+								Online.setOnline(false);//修改网络状态
+								item.replyCount = item.replyCount || 0;
+								item.replyCount += 1;//添加属性并+1(作为需要上传的标志)
+							} else {//其他错误
+								console.log(response.data);
+							}
+						});
+					} else {//无网络连接,如无网络错误操作
+						item.replyCount = item.replyCount || 0;
+						item.replyCount += 1;
+					}
+				} else {//不是当前的物料
+					$scope.overError = true;
+				}
+			} else {
+				Ring.error();
+				$scope.selectedId = 0;
+				$scope.noProduct = true;
+			}
+			$scope.productCode = '';
+		};
+		
+		$scope.search = function($event, productCode){
+			if($event.keyCode == 13) {//Enter事件
+				$scope.scan(productCode);
+			}
+		};
+		
+		$scope.pecent = function(numerator, denominator){//输入分母分子获取对应的百分数
+			return ((numerator/denominator).toFixed(2) * 100);
+		};
+	});
+	
+	app.controller('UploadCtrl', function($scope, $rootScope, PurcOrderItem, Online){
+		$scope.upLoadItems = [];
+		
+		angular.forEach($rootScope.orders, function(value,key){//先去获取需要上传的Item(明细)
+			angular.forEach(value.orderItems, function(item, key){
+				if(item.replyCount) $scope.upLoadItems.push(item);
+			});
+		});
+		
+		$scope.upload = function(){//一键上传操作
+			$scope.netError = false;
+			angular.forEach($scope.upLoadItems, function(item, key){
+				if(Online.getOnline()) {//判断是否有网
+					item.loading = 'fa fa-spinner fa-spin';//正在上传
+					//上传回复,replyCount作为回复数
+					PurcOrderItem.reply({orderItemId: item.id}, {delivery: new Date().getTime(), qty: item.replyCount, remark: '测试离线后上传'}, 
+					function(data){
+						item.loading = 'fa fa-check-square';//上传成功
+						item.uploadOk = true;
+						item.replyCount = 0;
+					}, function(response){//请求发生错误
+						item.loading = 'fa fa-exclamation-triangle text-danger';//上传失败
+						if(response.status == 0) {//无网络错误
+							Online.setOnline(false);//修改网络状态
+							$scope.netError = true;
+						} else {//其他错误
+							console.log(response.data);
+						}
+					});
+				} else {
+					$scope.netError = true;//断网提示
+					return;
+				}
+			});
+		};
+	});
+	
+	return app;
+});

+ 35 - 0
src/main/webapp/resources/js/index/mobile.storage.main.js

@@ -0,0 +1,35 @@
+require.config({
+	baseUrl : 'static',
+	paths : {
+		'app' : 'js/index',
+		'angular' : 'lib/angular/angular',
+		'ngAnimate': 'lib/angular/angular-animate.min',
+		'toaster' : 'lib/angular/angular-toaster.min',
+		'd3' : 'lib/angular/d3.min',
+		'charts' : 'lib/angular/angular-charts.min',
+		'common' : 'js/common',
+		'service' : 'js/index/services',
+		'ui.router' : 'lib/angular/angular-ui-router.min',
+		'ui.bootstrap' : 'lib/angular/ui-bootstrap-tpls',
+		'ngTable' : 'lib/angular/ng-table',
+		'ngResource' : 'lib/angular/angular-resource.min'
+	},
+	shim : {
+		'angular' : {
+			'exports' : 'angular'
+		},
+		'ngAnimate' : ['angular'],
+		'ngResource' : ['angular'],
+		'toaster' : ['angular', 'ngAnimate'],
+		'charts' : ['angular', 'd3'],
+		'ui.router' : ['angular'],
+		'ui.bootstrap' : [ 'angular' ],
+		'ngTable' : {
+			'exports' : 'ngTable',
+			'deps' : [ 'angular' ]
+		}
+	}
+});
+require([ 'app/mobile.storage.app' ], function(app) {
+	app.init();
+});

BIN
src/main/webapp/resources/ring/error.wav


BIN
src/main/webapp/resources/ring/success.wav


+ 35 - 0
src/main/webapp/resources/tpl/index_mobile/storage/index.html

@@ -0,0 +1,35 @@
+<style>
+	.m-b-10 {
+		margin-bottom: 10px;
+	}
+	
+	.row { 
+		margin-left: 0px;
+		margin-right: 0px;
+	}
+</style>
+<div  style="min-height: 500px;" ng-controller="IndexCtrl">
+	<div class="row" style="padding-top: 40px;">
+		<div class="col-sm-8 col-sm-offset-2 col-xs-8 col-xs-offset-2 text-center"><h3>UAS仓储管理系统</h3></div>
+	</div>
+	<div class="row">
+		<a ng-href="#/input" class="btn btn-default col-sm-8 col-sm-offset-2 col-xs-8 col-xs-offset-2 m-b-10 text-success">
+			<i class="fa fa-sign-in text-success"></i> 入库作业
+		</a>
+	</div>
+	<div class="row">
+		<a class="btn btn-default col-sm-8 col-sm-offset-2 col-xs-8 col-xs-offset-2 m-b-10">
+			<i class="fa fa-sign-out text-warning"></i> 出库作业
+		</a>
+	</div>
+	<div class="row">
+		<a ng-href="#/upload" class="btn btn-default col-sm-8 col-sm-offset-2 col-xs-8 col-xs-offset-2 m-b-10 text-success">
+			<i class="fa fa-cog"></i> 需要上传 <span class="text-num">{{getNeedUpCount()}}</span>
+		</a>
+	</div>
+	<div class="row">
+		<a class="btn btn-default col-sm-8 col-sm-offset-2 col-xs-8 col-xs-offset-2 m-b-10 text-success">
+			<i class="fa fa-cogs"></i> 入库作业
+		</a>
+	</div>
+</div>

+ 56 - 0
src/main/webapp/resources/tpl/index_mobile/storage/input.html

@@ -0,0 +1,56 @@
+<style>
+	.m-b-10 {
+		margin-bottom: 10px;
+	}
+	.m-t-10 {
+		margin-top: 10px;
+	}
+	.row { 
+		margin-left: 0px;
+		margin-right: 0px;
+	}
+	.border {
+		border: solid 1px #DDDDDD;
+		border-radius: 4px;
+	}
+	.border-error {
+		border: solid 1px #FF6666;
+		border-radius: 4px;
+	}
+	.selected {
+		border-color: #0099CC;
+	}
+</style>
+
+<div ng-controller="InputCtrl" style="min-height: 500px;">
+	<div class="row m-b-10 m-t-10">
+		<div class="col-xs-10 col-xs-offset-1 col-sm-10 col-sm-offset-1">
+			<div class=" input-group input-group-sm input-trigger">
+				<input type="search" class="form-control" placeholder="单据条码号" ng-model="batchCode" ng-keyup="search($event,batchCode)"> 
+				<span class="input-group-btn">
+                	<button ng-click="getOrder(batchCode)" type="button" class="btn btn-primary" ng-disabled="!batchCode">
+                		<i class="fa fa-search"></i>
+                	</button>
+              	</span>
+			</div>
+		</div>
+	</div>
+	<div class="row m-b-10">
+		<div class="col-xs-10 col-xs-offset-1 col-sm-10 col-sm-offset-1">
+			<div class="text-muted" ng-show="orders.length == 0">目前还没有下载好的入库单呢...</div>
+		</div>
+	</div>
+	<div class="row m-b-10" ng-show="getError">
+		<div class="col-xs-10 col-xs-offset-1 col-sm-10 col-sm-offset-1 border-error">
+			<div class="text-muted">获取入库单失败哦-{{errorCode}}</div>
+		</div>
+	</div>
+	<div class="row m-b-10" ng-repeat="order in orders">
+		<div class="col-xs-10 col-xs-offset-1 col-sm-10 col-sm-offset-1 border" ng-class="{'selected': selectedId == order.id}" ng-click="operate(order)">
+			<div>{{order.code}}<span class="right text-primary bold">{{$index + 1}}</span></div>
+			<div class="text-muted text-num"><span class="left" ng-bind="order.date | date:'yyyy-MM-dd'"></span>
+				<span class="right">共{{order.orderItems.length}}种  {{totalQty(order)}}件物料</span>
+			</div>
+		</div>
+	</div>
+</div>

+ 103 - 0
src/main/webapp/resources/tpl/index_mobile/storage/inputOperation.html

@@ -0,0 +1,103 @@
+<style>
+	.m-b-10 {
+		margin-bottom: 10px;
+	}
+	.m-t-10 {
+		margin-top: 10px;
+	}
+	.row { 
+		margin-left: 0px;
+		margin-right: 0px;
+	}
+	.border {
+		border: solid 1px #DDDDDD;
+		border-radius: 4px;
+	}
+	.selected {
+		border-color: #0099CC;
+	}
+	.full {
+		border-color: #33CC33;
+		border-size: 2px;
+	}
+	.order {
+		border-bottom: solid 1px #0066CC;
+	}
+	.qty {
+		display: table-cell;
+		width: 33%;
+	}
+	.error {
+		border: solid 1px #FF6666;
+		border-radius: 4px;
+	}
+	
+</style>
+
+<div ng-controller="InputOperationCtrl" style="min-height: 500px;">
+	<div class="row m-b-10 m-t-10">
+		<div class="col-xs-10 col-xs-offset-1 col-sm-10 col-sm-offset-1 text-center">
+			<h4>入库单作业</h4>
+		</div>
+	</div>
+	<div class="row m-b-10" ng-hide="order">
+		<div class="col-xs-10 col-xs-offset-1 col-sm-10 col-sm-offset-1">
+			<div class="text-muted">没有这样一条入库单哦...</div>
+		</div>
+	</div>
+	<div ng-show="order" class="row m-b-10">
+		<div class="col-xs-10 col-xs-offset-1 col-sm-10 col-sm-offset-1 order">
+			<div>
+				<div>
+					<span class="f-16">{{order.code}}</span>
+					&nbsp;&nbsp;<span class="text-muted text-num">{{order.date | date: 'yyyy-MM-dd'}}</span>
+				</div>
+				<div class="text-muted">
+					<span>客户:{{order.enterprise.enName}}</span>
+				</div>
+			</div>
+		</div>
+	</div>
+	<div ng-show="order" class="row m-b-10 m-t-10">
+		<div class="col-xs-10 col-xs-offset-1 col-sm-10 col-sm-offset-1">
+			<div class=" input-group input-group-sm input-trigger">
+				<input type="search" class="form-control" placeholder="物料条码号" ng-model="productCode"
+					ng-keyup="search($event,productCode)"> 
+				<span class="input-group-btn">
+                	<button ng-click="scan(productCode)" type="button" class="btn btn-success" ng-disabled="!productCode">
+                		<i class="fa fa-search-plus"></i>
+                	</button>
+              	</span>
+			</div>
+		</div>
+	</div>
+	<div class="row m-b-10"  ng-show="noProduct">
+		<div class="col-xs-10 col-xs-offset-1 col-sm-10 col-sm-offset-1 error">
+			<div class="text-muted">这个物料不是我们想要的哦...</div>
+		</div>
+	</div>
+	<div class="row m-b-10"  ng-show="overError">
+		<div class="col-xs-10 col-xs-offset-1 col-sm-10 col-sm-offset-1 error">
+			<div class="text-muted">咱这个物料够了哦...</div>
+		</div>
+	</div>
+	<div class="row m-b-10"  ng-show="!getOnline()">
+		<div class="col-xs-10 col-xs-offset-1 col-sm-10 col-sm-offset-1 error">
+			<div class="text-muted">断网模式下完成的操作需要手动上传哦...</div>
+		</div>
+	</div>
+	<div class="row m-b-10" ng-repeat="item in order.orderItems">
+		<div class="col-xs-10 col-xs-offset-1 col-sm-10 col-sm-offset-1 border" ng-class="{'selected': selectedId == item.id, 'full': item.replyQty == item.qty}">
+			<div>{{item.product.code}}<span class="right text-primary bold">{{$index + 1}}</span></div>
+			<div class="text-muted f-12"><span>{{item.product.title}}</span> - <span>{{item.product.spec}}</span></div>
+			<div style="border-top: solid 1px #EEEEEE;">
+				<div class="progress text-num">
+				  	<div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="{{item.replyQty || 0}}" 
+				  		aria-valuemin="0" aria-valuemax="{{item.qty}}" style="width: {{pecent(item.replyQty, item.qty) + '%'}};">
+				    	{{item.replyQty || 0}}/{{item.qty}} {{item.product.unit}}
+				  	</div>
+				</div>
+			</div>
+		</div>
+	</div>
+</div>

+ 57 - 0
src/main/webapp/resources/tpl/index_mobile/storage/needToUpload.html

@@ -0,0 +1,57 @@
+<style>
+	.m-b-10 {
+		margin-bottom: 10px;
+	}
+	.m-t-10 {
+		margin-top: 10px;
+	}
+	.row { 
+		margin-left: 0px;
+		margin-right: 0px;
+	}
+	.border {
+		border: solid 1px #DDDDDD;
+		border-radius: 4px;
+	}
+	.border-error {
+		border: solid 1px #FF6666;
+		border-radius: 4px;
+	}
+	.selected {
+		border-color: #0099CC;
+	}
+	.full {
+		border-color: #33CC33;
+		text-color: #33CC33;
+	}
+</style>
+
+<div ng-controller="UploadCtrl" style="min-height: 500px;">
+	<div class="row m-b-10 m-t-10">
+		<div ng-disabled="upLoadItems.length == 0" ng-click="upload()" class="col-xs-10 col-xs-offset-1 col-sm-10 col-sm-offset-1 btn btn-success">
+			<i class="fa fa-paper-plane-o"></i> 一键上传
+		</div>
+	</div>
+	<div ng-show="upLoadItems.length == 0" class="row m-b-10">
+		<div class="col-xs-10 col-xs-offset-1 col-sm-10 col-sm-offset-1">
+			<div class="text-muted">目前还没有需要上传的操作...</div>
+		</div>
+	</div>
+	<div ng-show="netError" class="row m-b-10">
+		<div class="col-xs-10 col-xs-offset-1 col-sm-10 col-sm-offset-1 border-error">
+			<div class="text-muted">断网咯...</div>
+		</div>
+	</div>
+	<div class="row m-b-10" ng-repeat="item in upLoadItems" ng-class="{'full': item.uploadOk}">
+		<div class="col-xs-10 col-xs-offset-1 col-sm-10 col-sm-offset-1 border">
+			<div>{{item.product.title}}<span class="right text-primary">{{$index + 1}}</span></div>
+			<div class="text-muted text-num">
+				<span class="left">{{item.product.code}}</span>
+				<span class="right text-success">
+					<i class="{{item.loading || 'fa fa-bookmark-o'}}"></i>
+					&nbsp;&nbsp;<i class="fa fa-cloud-upload"></i>{{item.replyCount}}
+				</span>
+			</div>
+		</div>
+	</div>
+</div>