Browse Source

git-svn-id: svn+ssh://10.10.101.21/source/platform/platform-b2b@742 f3bf4e98-0cf0-11e4-a00c-a99a8b9d557d

administrator 11 years ago
parent
commit
9dae834eff

+ 12 - 0
src/main/java/com/uas/platform/b2b/dao/PurchaseInquiryDao.java

@@ -4,6 +4,8 @@ import java.util.List;
 
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
 import org.springframework.stereotype.Repository;
 
 import com.uas.platform.b2b.model.PurchaseInquiry;
@@ -29,4 +31,14 @@ public interface PurchaseInquiryDao extends JpaSpecificationExecutor<PurchaseInq
 	 */
 	public List<PurchaseInquiry> findByEnUUAndSourceId(long enUU, long sourceId);
 
+	/**
+	 * 按询价单ID和明细供应商UU查找
+	 * 
+	 * @param vendUU
+	 * @param id
+	 * @return
+	 */
+	@Query("select p from PurchaseInquiry p inner join p.inquiryItems as i where i.vendUU = :vendUU and p.id = :id")
+	public List<PurchaseInquiry> findByVendUUAndId(@Param("vendUU") long vendUU, @Param("id") long id);
+
 }

+ 14 - 0
src/main/java/com/uas/platform/b2b/model/PurchaseOrderAllItem.java

@@ -123,6 +123,12 @@ public class PurchaseOrderAllItem {
 	 */
 	@Column(name = "pd_delivery")
 	private Date delivery;
+	
+	/**
+	 * 是否已结案
+	 */
+	@Column(name = "pd_end")
+	private Short end;
 
 	public Long getId() {
 		return id;
@@ -260,4 +266,12 @@ public class PurchaseOrderAllItem {
 	public void setStatus(Short status) {
 		this.status = status;
 	}
+
+	public Short getEnd() {
+		return end;
+	}
+
+	public void setEnd(Short end) {
+		this.end = end;
+	}
 }

+ 39 - 68
src/main/java/com/uas/platform/b2b/service/impl/PurchaseInquiryServiceImpl.java

@@ -58,30 +58,25 @@ public class PurchaseInquiryServiceImpl implements PurchaseInquiryService {
 			PurchaseInquiry inquiry = item.getInquiry();
 			if (item.getVendUserUU() != null) {
 				// Android
-				XingePusher.pushSingleAccountAndroid(item.getVendUserUU()
-						.toString(), "新增一条客户询价-", "单号:" + inquiry.getCode()
-						+ ",客户:" + inquiry.getEnterprise().getEnName(),
-						"com.sas.mobile.activity.PurchaseChangeActivity");
+				XingePusher.pushSingleAccountAndroid(item.getVendUserUU().toString(), "新增一条客户询价-", "单号:" + inquiry.getCode() + ",客户:"
+						+ inquiry.getEnterprise().getEnName(), "com.sas.mobile.activity.PurchaseChangeActivity");
 				// IOS
-				XingePusher.pushSingleAccountIOS(item.getVendUserUU()
-						.toString(), "新增一条客户询价-" + "单号:" + inquiry.getCode()
-						+ ",客户:" + inquiry.getEnterprise().getEnName());
+				XingePusher.pushSingleAccountIOS(item.getVendUserUU().toString(), "新增一条客户询价-" + "单号:" + inquiry.getCode() + ",客户:"
+						+ inquiry.getEnterprise().getEnName());
 			}
 		}
 	}
 
 	@Override
 	public List<PurchaseInquiryItem> findNotUploadReply() {
-		return purchaseInquiryItemDao.findByEnUUAndBackStatus(SystemSession
-				.getUser().getEnterprise().getUu(),
+		return purchaseInquiryItemDao.findByEnUUAndBackStatus(SystemSession.getUser().getEnterprise().getUu(),
 				(short) Status.NOT_UPLOAD.value());
 	}
 
 	@Override
 	public void onReplyUploadSuccess(String[] idArray) {
 		for (String id : idArray) {
-			PurchaseInquiryItem item = purchaseInquiryItemDao.findOne(Long
-					.parseLong(id));
+			PurchaseInquiryItem item = purchaseInquiryItemDao.findOne(Long.parseLong(id));
 			if (item != null) {
 				item.setBackStatus((short) Status.DOWNLOADED.value());
 				purchaseInquiryItemDao.save(item);
@@ -95,19 +90,13 @@ public class PurchaseInquiryServiceImpl implements PurchaseInquiryService {
 		// 将客户处理报价结果推送通知供应商联系人UU号
 		for (PurchaseInquiryItem item : inquiryItems) {
 			PurchaseInquiry inquiry = item.getInquiry();
-			String tittle = (item.getAgreed() == Constant.YES) ? "客户同意了您的报价"
-					: "客户不同意您的报价";
+			String tittle = (item.getAgreed() == Constant.YES) ? "客户同意了您的报价" : "客户不同意您的报价";
 			if (item.getVendUserUU() != null) {
 				// Android
-				XingePusher.pushSingleAccountAndroid(item.getVendUserUU()
-						.toString(), tittle, "物料:"
-						+ item.getProduct().getTitle() + ",客户:"
-						+ inquiry.getEnterprise().getEnName(),
-						"com.sas.mobile.activity.PurchaseChangeActivity");
+				XingePusher.pushSingleAccountAndroid(item.getVendUserUU().toString(), tittle, "物料:" + item.getProduct().getTitle() + ",客户:"
+						+ inquiry.getEnterprise().getEnName(), "com.sas.mobile.activity.PurchaseChangeActivity");
 				// IOS
-				XingePusher.pushSingleAccountIOS(item.getVendUserUU()
-						.toString(), tittle + "物料:"
-						+ item.getProduct().getTitle() + ",客户:"
+				XingePusher.pushSingleAccountIOS(item.getVendUserUU().toString(), tittle + "物料:" + item.getProduct().getTitle() + ",客户:"
 						+ inquiry.getEnterprise().getEnName());
 			}
 		}
@@ -115,16 +104,14 @@ public class PurchaseInquiryServiceImpl implements PurchaseInquiryService {
 
 	@Override
 	public List<PurchaseInquiryItem> findNotUploadInquiry() {
-		return purchaseInquiryItemDao.findByVendUUAndSendStatus(SystemSession
-				.getUser().getEnterprise().getUu(),
+		return purchaseInquiryItemDao.findByVendUUAndSendStatus(SystemSession.getUser().getEnterprise().getUu(),
 				(short) Status.NOT_UPLOAD.value());
 	}
 
 	@Override
 	public void onQuotationDownSuccess(String[] idArray) {
 		for (String id : idArray) {
-			PurchaseInquiryItem item = purchaseInquiryItemDao.findOne(Long
-					.parseLong(id));
+			PurchaseInquiryItem item = purchaseInquiryItemDao.findOne(Long.parseLong(id));
 			if (item != null) {
 				item.setSendStatus((short) Status.DOWNLOADED.value());
 				purchaseInquiryItemDao.save(item);
@@ -135,8 +122,7 @@ public class PurchaseInquiryServiceImpl implements PurchaseInquiryService {
 	@Override
 	public void reply(List<QuotationDown> downs) {
 		for (QuotationDown down : downs) {
-			PurchaseInquiryItem item = purchaseInquiryItemDao.findOne(down
-					.getB2b_id_id());
+			PurchaseInquiryItem item = purchaseInquiryItemDao.findOne(down.getB2b_id_id());
 			if (item != null) {
 				item.setMinOrderQty(down.getQu_minbuyqty());
 				item.setMinPackQty(down.getQu_minqty());
@@ -162,13 +148,11 @@ public class PurchaseInquiryServiceImpl implements PurchaseInquiryService {
 					// 消息推送
 					if (userUU != null && userUU != 0) {
 						// Android
-						XingePusher.pushSingleAccountAndroid(userUU.toString(),
-								"询价单回复", "单号:" + item.getInquiry().getCode()
-										+ ",第" + item.getNumber() + "行", "");
+						XingePusher.pushSingleAccountAndroid(userUU.toString(), "询价单回复",
+								"单号:" + item.getInquiry().getCode() + ",第" + item.getNumber() + "行", "");
 						// IOS
 						XingePusher.pushSingleAccountIOS(userUU.toString(),
-								"询价单回复" + "单号:" + item.getInquiry().getCode()
-										+ ",第" + item.getNumber() + "行");
+								"询价单回复" + "单号:" + item.getInquiry().getCode() + ",第" + item.getNumber() + "行");
 					}
 				}
 				purchaseInquiryItemDao.save(item);
@@ -178,16 +162,14 @@ public class PurchaseInquiryServiceImpl implements PurchaseInquiryService {
 
 	@Override
 	public List<PurchaseInquiryItem> findNotUploadInquiryReply() {
-		return purchaseInquiryItemDao.findByVendUUAndReplySendStatus(
-				SystemSession.getUser().getEnterprise().getUu(),
+		return purchaseInquiryItemDao.findByVendUUAndReplySendStatus(SystemSession.getUser().getEnterprise().getUu(),
 				(short) Status.NOT_UPLOAD.value());
 	}
 
 	@Override
 	public void onReplyDownSuccess(String[] idArray) {
 		for (String id : idArray) {
-			PurchaseInquiryItem item = purchaseInquiryItemDao.findOne(Long
-					.parseLong(id));
+			PurchaseInquiryItem item = purchaseInquiryItemDao.findOne(Long.parseLong(id));
 			if (item != null) {
 				item.setReplySendStatus((short) Status.DOWNLOADED.value());
 				purchaseInquiryItemDao.save(item);
@@ -197,16 +179,14 @@ public class PurchaseInquiryServiceImpl implements PurchaseInquiryService {
 
 	@Override
 	public List<PurchaseInquiryItem> findNotUploadInquiryReplyDecide() {
-		return purchaseInquiryItemDao.findByVendUUAndDecideStatus(SystemSession
-				.getUser().getEnterprise().getUu(),
+		return purchaseInquiryItemDao.findByVendUUAndDecideStatus(SystemSession.getUser().getEnterprise().getUu(),
 				(short) Status.NOT_UPLOAD.value());
 	}
 
 	@Override
 	public void onReplyDecideDownSuccess(String[] idArray) {
 		for (String id : idArray) {
-			PurchaseInquiryItem item = purchaseInquiryItemDao.findOne(Long
-					.parseLong(id));
+			PurchaseInquiryItem item = purchaseInquiryItemDao.findOne(Long.parseLong(id));
 			if (item != null) {
 				item.setDecideStatus((short) Status.DOWNLOADED.value());
 				purchaseInquiryItemDao.save(item);
@@ -216,22 +196,21 @@ public class PurchaseInquiryServiceImpl implements PurchaseInquiryService {
 
 	@Override
 	public Page<PurchaseInquiryItem> findAllByPageInfo(final PageInfo pageInfo) {
-		return purchaseInquiryItemDao.findAll(
-				new Specification<PurchaseInquiryItem>() {
+		return purchaseInquiryItemDao.findAll(new Specification<PurchaseInquiryItem>() {
 
-					public Predicate toPredicate(
-							Root<PurchaseInquiryItem> root,
-							CriteriaQuery<?> query, CriteriaBuilder builder) {
-						query.where(pageInfo
-								.getPredicates(root, query, builder));
-						return null;
-					}
-				}, pageInfo);
+			public Predicate toPredicate(Root<PurchaseInquiryItem> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
+				query.where(pageInfo.getPredicates(root, query, builder));
+				return null;
+			}
+		}, pageInfo);
 	}
 
 	@Override
 	public PurchaseInquiry findById(Long id) {
-		return purchaseInquiryDao.findOne(id);
+		List<PurchaseInquiry> inquiries = purchaseInquiryDao.findByVendUUAndId(SystemSession.getUser().getEnterprise().getUu(), id);
+		if (!CollectionUtils.isEmpty(inquiries))
+			return inquiries.get(0);
+		return null;
 	}
 
 	@Override
@@ -246,11 +225,9 @@ public class PurchaseInquiryServiceImpl implements PurchaseInquiryService {
 
 	@Override
 	public PurchaseInquiryItem reply(PurchaseInquiryItem inquiryItem) {
-		PurchaseInquiryItem item = purchaseInquiryItemDao.findOne(inquiryItem
-				.getId());
+		PurchaseInquiryItem item = purchaseInquiryItemDao.findOne(inquiryItem.getId());
 		if (item.getStatus() == Status.REPLIED.value()
-				|| (item.getReplySendStatus() != null && item
-						.getReplySendStatus() == Status.DOWNLOADED.value()))
+				|| (item.getReplySendStatus() != null && item.getReplySendStatus() == Status.DOWNLOADED.value()))
 			throw new IllegalStatusException("该询价单已经报价,不允许再次报价");
 		inquiryItem.setStatus((short) Status.REPLIED.value());
 		inquiryItem.setBackStatus((short) Status.NOT_UPLOAD.value());
@@ -263,13 +240,11 @@ public class PurchaseInquiryServiceImpl implements PurchaseInquiryService {
 			// 消息推送
 			if (userUU != null && userUU != 0) {
 				// Android
-				XingePusher.pushSingleAccountAndroid(userUU.toString(),
-						"询价单回复", "单号:" + item.getInquiry().getCode() + ",第"
-								+ item.getNumber() + "行", "");
+				XingePusher.pushSingleAccountAndroid(userUU.toString(), "询价单回复",
+						"单号:" + item.getInquiry().getCode() + ",第" + item.getNumber() + "行", "");
 				// IOS
-				XingePusher.pushSingleAccountIOS(userUU.toString(),
-						"询价单回复" + "单号:" + item.getInquiry().getCode() + ",第"
-								+ item.getNumber() + "行");
+				XingePusher.pushSingleAccountIOS(userUU.toString(), "询价单回复" + "单号:" + item.getInquiry().getCode() + ",第" + item.getNumber()
+						+ "行");
 			}
 		}
 		return purchaseInquiryItemDao.save(inquiryItem);
@@ -277,8 +252,7 @@ public class PurchaseInquiryServiceImpl implements PurchaseInquiryService {
 
 	@Override
 	public int getOnhandCount() {
-		return purchaseInquiryItemDao.getCountByVendUUAndStatus(SystemSession
-				.getUser().getEnterprise().getUu(),
+		return purchaseInquiryItemDao.getCountByVendUUAndStatus(SystemSession.getUser().getEnterprise().getUu(),
 				(short) Status.NOT_REPLY.value());
 	}
 
@@ -287,8 +261,7 @@ public class PurchaseInquiryServiceImpl implements PurchaseInquiryService {
 		PurchaseInquiryItem item = purchaseInquiryItemDao.findOne(itemId);
 		if (item != null) {
 			final PageInfo pageInfo = new PageInfo(1, 3, 1);
-			pageInfo.filter("vendUU", SystemSession.getUser().getEnterprise()
-					.getUu());
+			pageInfo.filter("vendUU", SystemSession.getUser().getEnterprise().getUu());
 			pageInfo.filter("productId", item.getProductId());
 			pageInfo.filter("status", (short) Status.REPLIED.value());
 			pageInfo.sorting("inquiry.date", Direction.DESC);
@@ -304,9 +277,7 @@ public class PurchaseInquiryServiceImpl implements PurchaseInquiryService {
 		if (!CollectionUtils.isEmpty(attachs)) {
 			long enUU = SystemSession.getUser().getEnterprise().getUu();
 			for (Attach attach : attachs) {
-				List<PurchaseInquiry> inquiries = purchaseInquiryDao
-						.findByEnUUAndSourceId(enUU,
-								Long.parseLong(attach.getSourceId()));
+				List<PurchaseInquiry> inquiries = purchaseInquiryDao.findByEnUUAndSourceId(enUU, Long.parseLong(attach.getSourceId()));
 				if (!CollectionUtils.isEmpty(inquiries)) {
 					PurchaseInquiry inquiry = inquiries.get(0);
 					attach.setRelativeTable("purc$inquiry");

+ 69 - 1
src/main/webapp/resources/css/index.css

@@ -1077,6 +1077,20 @@ a {
 	border: none;
 }
 
+.input-xs,.input-group-xs>.form-control,.input-group-xs>.input-group-addon,.input-group-xs>.input-group-btn>.btn
+	{
+	height: 26px;
+	padding: 0 5px;
+	font-size: 12px;
+	line-height: 1.5;
+	border-radius: 3px;
+}
+
+.input-group-xs .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn {
+	border-top-left-radius: 0;
+	border-bottom-left-radius: 0;
+}
+
 .ng-table-pager {
 	padding: 10px 15px;
 }
@@ -1084,6 +1098,53 @@ a {
 .ng-table-pager .pagination {
 	margin: 0;
 }
+
+.headerline {
+  	font-size: 24px;
+  	font-family: Microsoft YaHei,SimHei,Verdana;
+  	font-weight: 500;
+  	line-height: 22px;
+  	margin: 25px 0 25px -15px;
+  	clear: both;
+  	zoom: 1;
+  	border-top: 1px solid #eee;
+  	position: relative;
+  	font-size: 18px;
+}
+
+.headerline .index {
+	position: absolute;
+	top: -12px;
+	left: 0;
+	width: 25px;
+  	height: 24px;
+  	line-height: 24px;
+  	background: #56a022;
+  	color: #fff;
+  	text-align: center;
+  	border-radius: 0 2px 2px 0;
+  	z-index: 2;
+}
+
+.headerline .content {
+	position: absolute;
+	top: -12px;
+	left: 25px;
+	line-height: 24px;
+  	padding: 0 15px 0 10px;
+  	background: #fff;
+  	z-index: 2;
+}
+
+.headerline .end {
+	position: absolute;
+	top: -12px;
+	right: 0;
+	line-height: 24px;
+  	padding-left: 15px;
+  	background: #fff;
+  	z-index: 2;
+}
 /*process*/
 .progress.progress-sm {
 	height: 14px;
@@ -1281,7 +1342,14 @@ a {
   	text-align: center;
 }
 
+.table-hover > tbody > tr:hover {
+  	background-color: #d0e9c6;
+	-webkit-transition: all 0.15s ease-in-out;
+	-moz-transition: all 0.15s ease-in-out;
+	transition: all 0.15s ease-in-out;
+}
+
 .file {
 	color: #336699;
 	text-decoration: underline;
-}
+}

+ 193 - 7
src/main/webapp/resources/js/index/app.js

@@ -77,22 +77,34 @@ define([ 'toaster', 'charts', 'ngTable', 'common/services', 'service/Purc', 'ser
 			url : "/order",
 			templateUrl : "static/tpl/index/sale/order.html",
 			controller: 'SaleOrderCtrl'
-		}).state('sale.order.*', {
+		}).state('sale.order_detail', {
 			url : "/order/:id",
-			templateUrl : "static/tpl/index/sale/order.html",
-			controller: 'SaleOrderCtrl'
+			templateUrl : "static/tpl/index/sale/order_detail.html",
+			controller: 'SaleOrderDetailCtrl'
 		}).state('sale.change', {
 			url : "/change",
 			templateUrl : "static/tpl/index/sale/change.html",
 			controller: 'SaleChangeCtrl'
+		}).state('sale.change_detail', {
+			url : "/change/:id",
+			templateUrl : "static/tpl/index/sale/change_detail.html",
+			controller: 'SaleChangeDetailCtrl'
 		}).state('sale.notice', {
 			url : "/notice",
 			templateUrl : "static/tpl/index/sale/notice.html",
 			controller: 'SaleNoticeCtrl'
+		}).state('sale.notice_detail', {
+			url : "/notice/:id",
+			templateUrl : "static/tpl/index/sale/notice_detail.html",
+			controller: 'SaleNoticeDetailCtrl'
 		}).state('sale.send', {
 			url : "/send",
 			templateUrl : "static/tpl/index/sale/send.html",
 			controller: 'SaleSendCtrl'
+		}).state('sale.send_detail', {
+			url : "/send/:id",
+			templateUrl : "static/tpl/index/sale/send_detail.html",
+			controller: 'SaleSendDetailCtrl'
 		}).state('sale.forecast', {
 			url : "/forecast",
 			templateUrl : "static/tpl/index/sale/forecast.html",
@@ -429,8 +441,6 @@ define([ 'toaster', 'charts', 'ngTable', 'common/services', 'service/Purc', 'ser
 			}
 		});
 	});
-	app.controller('VendorCtrl', function($scope, $rootScope, VendorService){
-	});
 	var getState = function(active) {
 		var fn = 'get';
 		switch(active) {
@@ -593,6 +603,51 @@ define([ 'toaster', 'charts', 'ngTable', 'common/services', 'service/Purc', 'ser
 			
 		};
 	});
+	app.controller('SaleOrderDetailCtrl', function($scope, $stateParams, PurcOrder, PurcOrderItem, toaster){
+		var loadData = function() {
+			PurcOrder.get({id: $stateParams.id}, function(data){
+				$scope.order = data;
+				var sum = 0;
+				angular.forEach($scope.order.orderItems, function(item){
+					sum += item.qty * item.price;
+				});
+				$scope.order.total = sum;
+			});
+		};
+		loadData();
+		$scope.getReply = function(item) {
+			if(!item.replies) {
+				PurcOrderItem.getReply({orderItemId: item.id}, function(replies){
+					item.replies = replies;
+				});
+			}
+		};
+		$scope.openDatePicker = function($event, item, openParam) {
+			$event.preventDefault();
+		    $event.stopPropagation();
+		    item[openParam] = !item[openParam];
+		};
+		$scope.onReplyClick = function(item) {
+			if(item.reply) {
+				if(!item.reply.qty) {
+					toaster.pop('warning', '提示', '请填写回复数量!');
+					return;
+				}
+				var reply = angular.copy(item.reply);
+				if(reply.delivery) {
+					if(typeof reply.delivery == 'object')
+						reply.delivery = reply.delivery.getTime();
+				} else
+					reply.delivery = item.delivery;
+				PurcOrderItem.reply({orderItemId: item.id}, reply, function(){
+					toaster.pop('info', '提示', '回复成功');
+					loadData();
+				}, function(response){
+					toaster.pop('error', '回复失败', response.data);
+				});
+			}
+		};
+	});
 	app.controller('SaleChangeCtrl', function($scope, $rootScope, $filter, PurcChange, ngTableParams, toaster, BaseService, PurcChangeHis){
 		$scope.active = 'todo';
 		$scope.agreedText = '全部';
@@ -662,6 +717,31 @@ define([ 'toaster', 'charts', 'ngTable', 'common/services', 'service/Purc', 'ser
 			}
 		};
 	});
+	app.controller('SaleChangeDetailCtrl', function($scope, $stateParams, PurcChange, toaster){
+		var loadData = function() {
+			PurcChange.get({id: $stateParams.id}, function(data){
+				$scope.change = data;
+			});
+		};
+		loadData();
+		$scope.openDatePicker = function($event, item, openParam) {
+			$event.preventDefault();
+		    $event.stopPropagation();
+		    item[openParam] = !item[openParam];
+		};
+		
+		$scope.onReplyClick = function(change) {
+			if(change.$agreed) {
+				var reply = {id: change.id, agreed: Number(change.$agreed), replyRemark: change.replyRemark};
+				PurcChange.reply({changeId: change.id}, reply, function(){
+					toaster.pop('info', '提示', '回复成功');
+					loadData();
+				}, function(response){
+					toaster.pop('error', '回复失败', response.data);
+				});
+			}
+		};
+	});
 	app.controller('SaleInquiryCtrl', function($scope, $rootScope, $filter, PurcInquiry, ngTableParams, toaster, BaseService, PurcInquiryHis){
 		$scope.active = 'todo';
 		$scope.agreedText = '全部';
@@ -790,6 +870,86 @@ define([ 'toaster', 'charts', 'ngTable', 'common/services', 'service/Purc', 'ser
 			}
 		};
 	});
+	app.controller('SaleInquiryDetailCtrl', function($scope, $stateParams, PurcInquiry, toaster){
+		var loadData = function() {
+			PurcInquiry.get({id: $stateParams.id}, function(data){
+				$scope.inquiry = data;
+			});
+		};
+		loadData();
+		$scope.getMinDate = function(item) {
+			return $filter('date')(item.inquiry.date, 'yyyy-MM-dd');
+		};
+		
+		$scope.addStep = function(inquiryItem) {
+			if(inquiryItem.replies.length >= 10) {
+				toaster.pop('warning', '提示', '最多支持10个分段!');
+			} else
+				inquiryItem.replies.push({});
+		};
+		
+		$scope.removeStep = function(inquiryItem, stepIndex) {
+			inquiryItem.replies.splice(stepIndex, 1);
+		};
+		
+		$scope.openDatePicker = function($event, item, openParam) {
+			$event.preventDefault();
+		    $event.stopPropagation();
+		    item[openParam] = !item[openParam];
+		};
+		
+		$scope.getHistory = function(item) {
+			if(!item.history) {
+				PurcInquiry.getHistory({itemId: item.id}, function(data){
+					item.history = data;
+				});
+			}
+		};
+		
+		$scope.isValid = function(item, withSteps) {
+			var bool = item.replies && item.replies[0].price > 0;
+			if(!withSteps || !bool)
+				return bool;
+			angular.forEach(item.replies, function(r, i){
+				bool = (i > 0 ? r.lapQty : 1) && r.price;
+			});
+			return bool;
+		};
+		
+		$scope.onReplyClick = function(item, withSteps) {
+			if(item.vendFromDate instanceof Date) {
+  				item.vendFromDate = item.vendFromDate.getTime();
+  			}
+  			if(item.vendToDate instanceof Date) {
+  				item.vendToDate = item.vendToDate.getTime();
+  			}
+  			if(item.vendFromDate > item.vendToDate) {
+  				toaster.pop('warning', '警告', '有效开始日期不能超过有效截止日期');
+  				return;
+  			}
+			var replies = [];
+			angular.forEach(item.replies, function(r, i){
+				if((i > 0 ? r.lapQty : 1) || r.price)
+					replies.push(r);
+			});
+			item.replies = replies;
+			if(withSteps) {
+				PurcInquiry.reply({itemId: item.id}, item, function(){
+					toaster.pop('info', '提示', '报价成功');
+					loadData();
+				}, function(response){
+					toaster.pop('error', '报价失败', response.data);
+				});
+			} else {
+				PurcInquiry.saveItem({itemId: item.id}, item, function(){
+					toaster.pop('info', '提示', '保存成功');
+					loadData();
+				}, function(response){
+					toaster.pop('error', '保存失败', response.data);
+				});
+			}
+		};
+	});
 	app.controller('SaleNoticeCtrl', function($scope, $rootScope, $filter, PurcNotice, ngTableParams, toaster, BaseService, PurcNoticeHis, $modal){
 		$scope.active = 'todo';
 		$scope.dateZoneText = '一个月内';
@@ -906,11 +1066,37 @@ define([ 'toaster', 'charts', 'ngTable', 'common/services', 'service/Purc', 'ser
 					
 				});
 			}
+		};	
+	});
+	app.controller('SaleNoticeDetailCtrl', function($scope, $stateParams, PurcNotice, toaster){
+		var loadData = function() {
+			PurcNotice.get({id: $stateParams.id}, function(data){
+				$scope.notice = data;
+			});
+		};
+		loadData();
+		$scope.openDatePicker = function($event, item, openParam) {
+			$event.preventDefault();
+		    $event.stopPropagation();
+		    item[openParam] = !item[openParam];
 		};
 		
-		
+		$scope.onReplyClick = function(notice) {
+			if(!notice.send || !notice.send.qty || notice.send.qty > notice.qty - (notice.endQty || 0)) {
+				toaster.pop('warning', '警告', '数量填写错误!');
+			} else if(!notice.send.code) {
+				toaster.pop('warning', '警告', '请填写发货单号!');
+			} else {
+				var send = {code: notice.send.code, sendItems: [{qty: notice.send.qty}]};
+				PurcNotice.save({id: notice.id}, send, function(){
+					toaster.pop('info', '提示', '发货成功');
+					loadData();
+				}, function(response){
+					toaster.pop('error', '失败', response);
+				});
+			}
+		};
 	});
-	
 	app.controller('SaleNoticeSendByBatchCtrl', function($scope, $modalInstance, Symbol, selectedNotices, PurcNotice, toaster){
 		$scope.notices = selectedNotices;
 		$scope.currency = Symbol.currency;//将币别转化为对应的符号

+ 5 - 24
src/main/webapp/resources/tpl/index/sale/change.html

@@ -92,20 +92,6 @@
 	padding-left: 20px;
 }
 
-.input-xs,.input-group-xs>.form-control,.input-group-xs>.input-group-addon,.input-group-xs>.input-group-btn>.btn
-	{
-	height: 26px;
-	padding: 0 5px;
-	font-size: 12px;
-	line-height: 1.5;
-	border-radius: 3px;
-}
-
-.input-group-xs .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn {
-	border-top-left-radius: 0;
-	border-bottom-left-radius: 0;
-}
-
 </style>
 <div class="block">
 <div class="loading in" ng-class="{'in': loading}">
@@ -237,8 +223,8 @@
 						ng-model="change.$selected">
 					</span> <span class="text-num text-bold"
 						ng-bind="::change.date | date:'yyyy-MM-dd'"></span> <span>流水号:<a
-						class="text-num" ng-bind="::change.code" href="#"></a></span> <span>订单:<a
-						class="text-num text-bold" ng-bind="::change.order.code" href="#"></a></span>
+						class="text-num" ng-bind="::change.code" ui-sref="sale.change_detail({id:change.id})" target="_blank"></a></span> <span>订单:<a
+						class="text-num text-bold" ng-bind="::change.order.code" ui-sref="sale.order_detail({id:change.order.id})" target="_blank"></a></span>
 				</div>
 			</td>
 			<td colspan="3"><a href="#"
@@ -300,14 +286,9 @@
 		</tr>
 		<tr class="order-bd" ng-repeat="item in ::change.orderChangeItems">
 			<td class="product">
-				<div class="text-num text-bold">
-					<a href="#" ng-bind="::item.newProduct.code"></a>
-				</div>
-				<div>
-					<a href="#" ng-bind="::item.newProduct.title"></a>
-				</div>
-				<div class="text-muted"
-					ng-bind="::item.newProduct.spec"></div>
+				<div class="text-num text-bold" ng-bind="::item.newProduct.code"></div>
+				<div ng-bind="::item.newProduct.title"></div>
+				<div class="text-muted" ng-bind="::item.newProduct.spec"></div>
 			</td>
 			<td class="text-center">
 				<div class="text-num"

+ 196 - 0
src/main/webapp/resources/tpl/index/sale/change_detail.html

@@ -0,0 +1,196 @@
+<div class="pane base-info">
+	<div class="pane-header">
+		客户采购变更单<a href="#" class="pull-right text-simple"><i
+			class="fa fa-print fa-fw"></i>打印</a>
+	</div>
+	<div class="pane-body">
+		<div class="headerline">
+			<span class="index">1</span> <span class="content">单据信息</span>
+		</div>
+		<div class="row row-sm item">
+			<div class="col-xs-3">
+				<span class="title">流水号</span>
+				<div class="content" ng-bind="::change.code"></div>
+			</div>
+			<div class="col-xs-3">
+				<span class="title">日期</span>
+				<div class="content" ng-bind="::change.date | date:'yyyy-MM-dd'"></div>
+			</div>
+			<div class="col-xs-6">
+				<span class="title">客户</span>
+				<div class="content" ng-bind="::change.order.enterprise.enName"></div>
+			</div>
+		</div>
+		<div class="row row-sm item">
+			<div class="col-xs-3">
+				<span class="title">录单人</span>
+				<div class="content" ng-bind="::change.recorder"></div>
+			</div>
+			<div class="col-xs-9">
+				<span class="title">备注</span>
+				<div class="content" ng-bind="::change.remark"></div>
+			</div>
+		</div>
+		<div class="headerline">
+			<span class="index">2</span> <span class="content">原采购单</span>
+		</div>
+		<div class="row row-sm item">
+			<div class="col-xs-3">
+				<span class="title">采购单号</span>
+				<div class="content">
+					<a ng-bind="::change.order.code"
+						ui-sref="sale.order_detail({id:change.order.id})" target="_blank"></a>
+				</div>
+			</div>
+			<div class="col-xs-3">
+				<span class="title">日期</span>
+				<div class="content"
+					ng-bind="::change.order.date | date:'yyyy-MM-dd'"></div>
+			</div>
+			<div class="col-xs-3">
+				<span class="title">采购类型</span>
+				<div class="content" ng-bind="::change.order.type"></div>
+			</div>
+		</div>
+		<div class="row row-sm item">
+			<div class="col-xs-3">
+				<span class="title">采购员</span>
+				<div class="content" ng-bind="::change.order.user.userName"></div>
+			</div>
+			<div class="col-xs-9">
+				<span class="title">交货地址</span>
+				<div class="content" ng-bind="::change.order.shipAddress"></div>
+			</div>
+		</div>
+		<div class="headerline">
+			<span class="index">3</span> <span class="content">交易信息变更</span>
+		</div>
+		<div class="row row-sm item">
+			<div class="col-xs-3">
+				<span class="title">币别</span>
+				<div class="content">
+					<span
+						ng-class="{'text-inverse': change.newCurrency != change.order.currency}"
+						ng-bind="::change.newCurrency"></span> <s
+						ng-show="change.newCurrency != change.order.currency"
+						class="text-muted" ng-bind="::change.order.currency"></s>
+				</div>
+			</div>
+			<div class="col-xs-3">
+				<span class="title">汇率</span>
+				<div class="text-num content">
+					<span
+						ng-class="{'text-inverse': change.newRate != change.order.rate}"
+						ng-bind="::change.newRate"></span> <s
+						ng-show="change.newRate != change.order.rate" class="text-muted"
+						ng-bind="::change.order.rate"></s>
+				</div>
+			</div>
+			<div class="col-xs-6">
+				<span class="title">付款方式</span>
+				<div class="content">
+					<span
+						ng-class="{'text-inverse': change.newPayments != change.order.payments}"
+						ng-bind="::change.newPayments"></span> <s
+						ng-show="change.newPayments != change.order.payments"
+						class="text-muted" ng-bind="::change.order.payments"></s>
+				</div>
+			</div>
+		</div>
+		<div class="headerline">
+			<div class="index">4</div>
+			<div class="content">商品变更详情</div>
+			<div class="end" ng-show="change.status == 200">
+				<a class="btn btn-sm btn-default"
+					ng-click="change.$editing=!change.$editing"><i
+					class="fa fa-share fa-fw"></i>我要回复</a>
+			</div>
+		</div>
+		<div class="row row-sm item" ng-if="change.$editing">
+			<div class="col-xs-3">
+				<div class="form-group pull-right" ng-init="change.$agreed = 1">
+					<label class="radio-inline"> <input type="radio"
+						ng-model="change.$agreed" value="1"> 同意
+					</label> <label class="radio-inline"> <input type="radio"
+						ng-model="change.$agreed" value="0"> 不同意
+					</label>
+				</div>
+			</div>
+			<div class="col-xs-7">
+				<div class="form-group">
+					<input type="text" ng-model="change.replyRemark"
+						class="form-control input-xs" placeholder="回复备注">
+				</div>
+			</div>
+			<div class="col-xs-2">
+				<div class="btn-group btn-group-xs btn-group-justified">
+					<div class="btn-group btn-group-xs">
+						<button type="button" class="btn btn-info btn-line" ng-click="onReplyClick(change)">确认回复</button>
+					</div>
+					<div class="btn-group btn-group-xs">
+						<button type="button" class="btn btn-default btn-line" ng-click="change.$editing=!change.$editing">取消</button>
+					</div>
+				</div>
+			</div>
+		</div>
+		<div class="block">
+			<table class="block table table-default table-striped table-hover">
+				<thead>
+					<tr class="header">
+						<th>商品</th>
+						<th>单价</th>
+						<th>数量</th>
+						<th width="120">交货日期</th>
+						<th width="140">变更内容</th>
+						<th width="70">操作</th>
+					</tr>
+				</thead>
+				<tbody>
+					<tr ng-repeat="item in change.orderChangeItems track by item.id">
+						<td>
+							<div class="text-num text-bold" ng-bind="::item.newProduct.code"></div>
+							<div ng-bind="::item.newProduct.title"></div>
+							<div class="text-muted" ng-bind="::item.newProduct.spec"></div>
+						</td>
+						<td class="text-center">
+							<div class="text-num"
+								ng-class="{'text-inverse': item.newPrice != item.orderItem.price}"
+								title="{{item.newPrice}}" ng-bind="::item.newPrice"></div>
+							<div ng-show="item.newPrice != item.orderItem.price">
+								<s class="text-num text-muted" ng-bind="::item.orderItem.price"></s>
+							</div>
+						</td>
+						<td class="text-center">
+							<div class="text-num"
+								ng-class="{'text-inverse': item.newQty != item.orderItem.qty}"
+								title="{{item.newQty}}" ng-bind="::item.newQty"></div>
+							<div ng-show="item.newQty != item.orderItem.qty">
+								<s class="text-num text-muted" title="{{item.orderItem.qty}}"
+									ng-bind="::item.orderItem.qty"></s>
+							</div>
+							<div class="text-muted" ng-bind="::item.newProduct.unit"></div>
+						</td>
+						<td class="text-center">
+							<div class="text-num"
+								ng-class="{'text-inverse': item.newDelivery != item.orderItem.delivery}"
+								ng-bind="::item.newDelivery | date:'yyyy-MM-dd'"></div>
+							<div ng-show="item.newDelivery != item.orderItem.delivery">
+								<s class="text-num text-muted"
+									ng-bind="::item.orderItem.delivery | date:'yyyy-MM-dd'"></s>
+							</div>
+						</td>
+						<td colspan="2">
+							<div ng-bind="::item.description"></div>
+							<div ng-if="change.agreed == 1" class="block">
+								<span class="text-trans success">已同意</span>
+							</div>
+							<div ng-if="change.agreed == 0" class="block">
+								<span class="text-trans warning">不同意</span>
+							</div>
+						</td>
+					</tr>
+				</tbody>
+			</table>
+		</div>
+	</div>
+</div>

+ 0 - 0
src/main/webapp/resources/tpl/index/sale/notice_detail.html


+ 3 - 17
src/main/webapp/resources/tpl/index/sale/order.html

@@ -92,20 +92,6 @@
 	padding-left: 20px;
 }
 
-.input-xs,.input-group-xs>.form-control,.input-group-xs>.input-group-addon,.input-group-xs>.input-group-btn>.btn
-	{
-	height: 26px;
-	padding: 0 5px;
-	font-size: 12px;
-	line-height: 1.5;
-	border-radius: 3px;
-}
-
-.input-group-xs .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn {
-	border-top-left-radius: 0;
-	border-bottom-left-radius: 0;
-}
-
 </style>
 <div class="block">
 <div class="loading in" ng-class="{'in': loading}">
@@ -228,7 +214,7 @@
 						ng-model="order.$selected" ng-click="checkOne(order)">
 					</span> <span class="text-num text-bold"
 						ng-bind="::order.date | date:'yyyy-MM-dd'"></span> <span>订单号:<a
-						class="text-num" ng-bind="::order.code" ui-sref="sale.order({id: order.id})"></a></span>
+						class="text-num" ng-bind="::order.code" ui-sref="sale.order_detail({id:order.id})" target="_blank"></a></span>
 				</div>
 			</td>
 			<td colspan="3"><a href="#" ng-bind="::order.enterprise.enName"></a></td>
@@ -249,10 +235,10 @@
 			ng-if="!order.$collapsed">
 			<td class="product">
 				<div class="text-num text-bold">
-					<a href="#" ng-bind="::item.product.code"></a>
+					<span href="#" ng-bind="::item.product.code"></span>
 				</div>
 				<div>
-					<a href="#" ng-bind="::item.product.title"></a>
+					<span href="#" ng-bind="::item.product.title"></span>
 				</div>
 				<div class="text-muted"
 					ng-bind="::item.product.spec"></div>

+ 201 - 0
src/main/webapp/resources/tpl/index/sale/order_detail.html

@@ -0,0 +1,201 @@
+<div class="pane base-info">
+	<div class="pane-header">
+		客户采购单<a href="#" class="pull-right text-simple"><i
+			class="fa fa-print fa-fw"></i>打印</a>
+	</div>
+	<div class="pane-body">
+		<div class="headerline">
+			<span class="index">1</span> <span class="content">采购资料</span>
+		</div>
+		<div class="row row-sm item">
+			<div class="col-xs-3">
+				<span class="title">采购单号</span>
+				<div class="content" ng-bind="::order.code"></div>
+			</div>
+			<div class="col-xs-3">
+				<span class="title">日期</span>
+				<div class="content" ng-bind="::order.date | date:'yyyy-MM-dd'"></div>
+			</div>
+			<div class="col-xs-6">
+				<span class="title">客户</span>
+				<div class="content" ng-bind="::order.enterprise.enName"></div>
+			</div>
+		</div>
+		<div class="row row-sm item">
+			<div class="col-xs-3">
+				<span class="title">采购类型</span>
+				<div class="content" ng-bind="::order.type"></div>
+			</div>
+			<div class="col-xs-3">
+				<span class="title">录单人</span>
+				<div class="content" ng-bind="::order.recorder"></div>
+			</div>
+			<div class="col-xs-3">
+				<span class="title">审批人</span>
+				<div class="content" ng-bind="::order.auditor"></div>
+			</div>
+			<div class="col-xs-3">
+				<span class="title">采购员</span>
+				<div class="content" ng-bind="::order.user.userName"></div>
+			</div>
+		</div>
+		<div class="headerline">
+			<span class="index">2</span> <span class="content">交易信息</span>
+		</div>
+		<div class="row row-sm item">
+			<div class="col-xs-3">
+				<span class="title">币别</span>
+				<div class="content" ng-bind="::order.currency"></div>
+			</div>
+			<div class="col-xs-3">
+				<span class="title">汇率</span>
+				<div class="content" ng-bind="::order.rate"></div>
+			</div>
+			<div class="col-xs-6">
+				<span class="title">付款方式</span>
+				<div class="content" ng-bind="::order.payments"></div>
+			</div>
+		</div>
+		<div class="row row-sm item">
+			<div class="col-xs-3">
+				<span class="title">金额</span>
+				<div class="content" ng-bind="::order.total"></div>
+			</div>
+			<div class="col-xs-9">
+				<span class="title">交货地址</span>
+				<div class="content" ng-bind="::order.shipAddress"></div>
+			</div>
+		</div>
+		<div class="headerline">
+			<span class="index">3</span> <span class="content">商品清单</span>
+		</div>
+		<div class="block">
+			<table class="block table table-default table-striped table-hover">
+				<thead>
+					<tr class="header">
+						<th>商品</th>
+						<th width="80">单价</th>
+						<th width="100">数量</th>
+						<th width="120">交货日期</th>
+						<th width="180">回复状态</th>
+						<th width="60">操作</th>
+					</tr>
+				</thead>
+				<tbody>
+					<tr ng-repeat="item in order.orderItems track by item.id">
+						<td>
+							<div class="text-num text-bold">
+								<span href="#" ng-bind="::item.product.code"></span>
+							</div>
+							<div>
+								<span href="#" ng-bind="::item.product.title"></span>
+							</div>
+							<div class="text-muted" ng-bind="::item.product.spec"></div>
+						</td>
+						<td class="text-center">
+							<div class="text-num" ng-bind="::item.price"></div>
+							<div class="text-muted">税率:{{::item.taxrate || 0}}%</div>
+						</td>
+						<td class="text-center">
+							<div class="text-num" ng-bind="::item.qty"></div>
+							<div class="text-muted" ng-bind="::item.product.unit"></div>
+							<div style="margin: 0 auto" ng-if="item.$editing">
+								<input type="text" ng-model="item.reply.qty"
+									ng-init="item.reply.qty=item.qty-item.replyQty"
+									class="form-control input-xs" placeholder="回复数量">
+							</div>
+						</td>
+						<td class="text-center">
+							<div class="text-num"
+								ng-bind="::item.delivery | date:'yyyy-MM-dd'"></div> <br>
+							<div style="margin: 0 auto"
+								class="input-group input-group-xs input-trigger"
+								ng-if="item.$editing">
+								<input type="text" ng-model="item.reply.delivery"
+									ng-init="item.reply.delivery=parseDate(item.delivery)"
+									class="form-control" placeholder="回复交期"
+									datepicker-popup="yyyy-MM-dd" is-open="item.$opened"
+									min-date="order.date" ng-required="true" current-text="今天"
+									clear-text="清除" close-text="关闭"
+									datepicker-options="{formatDayTitle: 'yyyy年M月', formatMonth: 'M月', showWeeks: false}"
+									ng-focus="openDatePicker($event, item, '$opened')"> <span
+									class="input-group-btn">
+									<button type="button" class="btn btn-default"
+										ng-click="openDatePicker($event, item, '$opened')">
+										<i class="fa fa-calendar"></i>
+									</button>
+								</span>
+							</div>
+						</td>
+						<td>
+							<div ng-show="!item.$editing">
+								<div ng-if="!item.replyQty" class="text-muted text-center">未回复</div>
+								<div ng-if="item.replyQty > 0 && item.replyQty < item.qty">
+									<div class="progress progress-sm">
+										<div class="progress-bar progress-bar-success"
+											ng-style="{'width': 100*item.replyQty/item.qty + '%'}">
+											<span class="sr-only"></span>
+										</div>
+									</div>
+									已回复 <span class="text-default">{{::item.replyQty}}</span> / <span>{{::item.qty}}</span>
+								</div>
+								<div ng-if="item.replyQty > 0" class="dropdown"
+									ng-class="{'text-center': item.replyQty>=item.qty}">
+									<a href="javascript:void(0);"
+										class="dropdown-toggle text-default"
+										ng-mouseover="getReply(item)">回复历史<i
+										class="fa fa-fw fa-angle-down"></i></a>
+									<div class="dropdown-menu pane" style="width: 270px;">
+										<div class="pane-body">
+											<ul class="list-unstyled list-menu">
+												<li ng-repeat="reply in ::item.replies">
+													<div class="row row-sm"
+														ng-class="{'text-inverse': $index==0}">
+														<div class="col-xs-6">数量{{::reply.qty}}</div>
+														<div class="col-xs-6">交期{{::reply.delivery |
+															date:'yyyy-MM-dd'}}</div>
+													</div>
+													<div class="text-muted">{{::reply.recorder}}{{::reply.date
+														| date:'yyyy-MM-dd HH:mm:ss'}}回复</div>
+												</li>
+											</ul>
+										</div>
+									</div>
+								</div>
+							</div>
+							<div style="margin: 0 auto" ng-if="item.$editing">
+								<br> <br> <input type="text"
+									ng-model="item.reply.remark" class="form-control input-xs"
+									placeholder="回复备注" />
+							</div>
+						</td>
+						<td class="text-center">
+							<div ng-if="item.replyQty>=item.qty" class="block">
+								<span class="text-trans success">已回复</span>
+							</div>
+							<div ng-if="item.end" class="block">
+								<span class="text-trans warning">已结案</span>
+							</div>
+							<div
+								ng-if="(!item.replyQty || item.replyQty<item.qty) && !item.end">
+								<div ng-show="!item.$editing">
+									<a ng-click="item.$editing=!item.$editing">回复</a>
+								</div>
+								<div ng-if="item.$editing">
+									<div>
+										<a ng-click="item.$editing=!item.$editing">取消</a>
+									</div>
+									<br>
+									<div>
+										<a ng-click="onReplyClick(item)" class="text-inverse">确认<br>回复
+										</a>
+									</div>
+								</div>
+							</div>
+						</td>
+					</tr>
+				</tbody>
+			</table>
+		</div>
+	</div>
+</div>