Browse Source

1.簽核修正

2.許協理價審同意後直接結案
3.蔡總審核權移除
gary
10994015 1 year ago
parent
commit
dc12285ad1
  1. 8
      wms/mkt/api/postNewElevatorPricereview.php
  2. 2
      wms/mkt/api/postPricereviewSign.php
  3. 51
      wms/mkt/api/updateSign.php
  4. 4
      wms/mkt/assets/js/pricereviewAlpine.js
  5. 76
      wms/mkt/exportTable.php
  6. 69
      wms/mkt/exportTable2.php
  7. 32
      wms/mkt/price_normal-index.php
  8. 8
      wms/mkt/pricereview-index.php
  9. 11
      wms/mkt/pricereviewCheck.php
  10. 6
      wms/mkt/table2excel/.babelrc
  11. 58
      wms/mkt/table2excel/.gitignore
  12. 192
      wms/mkt/table2excel/README.md
  13. 2
      wms/mkt/table2excel/dist/table2excel.core.js
  14. 18
      wms/mkt/table2excel/dist/table2excel.min.js
  15. 1123
      wms/mkt/table2excel/docs/index.html
  16. 17
      wms/mkt/table2excel/docs/js/exceljs.min.js
  17. 2
      wms/mkt/table2excel/docs/js/table2excel.core.js
  18. 11
      wms/mkt/table2excel/es5/constants.js
  19. 26
      wms/mkt/table2excel/es5/index.js
  20. 62
      wms/mkt/table2excel/es5/plugins/alignment.js
  21. 17
      wms/mkt/table2excel/es5/plugins/autoWidth.js
  22. 32
      wms/mkt/table2excel/es5/plugins/fill.js
  23. 24
      wms/mkt/table2excel/es5/plugins/font.js
  24. 16
      wms/mkt/table2excel/es5/plugins/form.js
  25. 16
      wms/mkt/table2excel/es5/plugins/hyperlink.js
  26. 40
      wms/mkt/table2excel/es5/plugins/index.js
  27. 202
      wms/mkt/table2excel/es5/table2excel.js
  28. 89
      wms/mkt/table2excel/es5/utils.js
  29. 42
      wms/mkt/table2excel/package.json
  30. 6
      wms/mkt/table2excel/src/constants.js
  31. 8
      wms/mkt/table2excel/src/index.js
  32. 49
      wms/mkt/table2excel/src/plugins/alignment.js
  33. 7
      wms/mkt/table2excel/src/plugins/autoWidth.js
  34. 27
      wms/mkt/table2excel/src/plugins/fill.js
  35. 16
      wms/mkt/table2excel/src/plugins/font.js
  36. 8
      wms/mkt/table2excel/src/plugins/form.js
  37. 8
      wms/mkt/table2excel/src/plugins/hyperlink.js
  38. 15
      wms/mkt/table2excel/src/plugins/index.js
  39. 149
      wms/mkt/table2excel/src/table2excel.js
  40. 81
      wms/mkt/table2excel/src/utils.js
  41. 26
      wms/mkt/table2excel/webpack.core.config.js
  42. 23
      wms/mkt/table2excel/webpack.umd.config.js

8
wms/mkt/api/postNewElevatorPricereview.php

@ -684,6 +684,10 @@ try{
$manager = "M0137";
}
$sign1 = "$manager,,"; //區處長
//新梯區處長自己填價審 ,審核直接通過
if($creater == "M0033" || $creater == "M0054" || $creater == "M0086" || $creater == "M0137" ){
$sign1 = $creater . ",Y,".date('Y-m-d H:i:s');
}
$sign2 =$ekind == '汰改'? "M0012,," : NULL; // 業務承辦人
$sign3 = $ekind == '汰改' ? "M0008,," : "M0060,,"; //業務部協理
$signArr = [
@ -692,8 +696,8 @@ try{
$sign3,
];
$sign_total = count(array_filter($signArr, fn($item)=> $item != NULL));
//是否呈核至總經理(M0006)
if($price_rate < 80 || $special_fee > 0){
//是否呈核至總經理(M0006) ,暫時不送至總經理,所以加入false
if((false && $price_rate < 80 || $special_fee > 0)){
$sign4 = "M0006,,";
$sign_total += 1;
}else{

2
wms/mkt/api/postPricereviewSign.php

@ -97,7 +97,7 @@ try{
//待簽通知
if($form_key == null){
$sql_str = "SELECT form_key FROM flow WHERE form_id = :form_id";
$sql_str = "SELECT form_key FROM flow WHERE form_id = :form_id AND system_id = 'prm' AND (flow_id='prm01' OR flow_id='prm02')";
$stmt = $conn->prepare($sql_str);
$stmt->bindParam(':form_id', $mid);
$stmt->execute();

51
wms/mkt/api/updateSign.php

@ -0,0 +1,51 @@
<?php
require_once "../conn.php";
if(!isset($_GET['id'])) exit;
$id = $_GET['id'];
if($id!=969) exit;
$sql_str = "SELECT * FROM pricereview_sign";
$stmt = $conn->prepare($sql_str);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach($result as $sign){
$endSign = false;
if(explode(",", $sign['sign3'])[1] == "Y"){
$newSign3 = str_replace("Y", "YY", $sign['sign3']);
$sign4_is_null = $sign['sign4'] == null ? true : false;
$sql_str = $sign4_is_null ? "UPDATE pricereview_sign SET sign3 = :sign3 WHERE id = :id" : "UPDATE pricereview_sign SET sign3 = :sign3, sign4 = NULL, sign_total = sign_total - 1 WHERE id = :id";
$stmt = $conn->prepare($sql_str);
$stmt->bindParam(':sign3', $newSign3);
$stmt->bindParam(':id', $sign['id']);
$stmt->execute();
$sql_str = "UPDATE pricereview_main SET status = 'YY' WHERE id = :id AND status = 'YS' ";
$stmt = $conn->prepare($sql_str);
$stmt->bindParam(':id', $sign['mid']);
$stmt->execute();
$sql_str = "UPDATE flow SET flow_code = 'Z' WHERE form_id = :id AND system_id = 'prm' AND (flow_id = 'prm01' OR flow_id = 'prm02')";
$stmt = $conn->prepare($sql_str);
$stmt->bindParam(':id', $sign['mid']);
$stmt->execute();
echo $sign['mid'];
echo "<br>";
}else{
if($sign['sign4'] != NULL){
$sql_str = "UPDATE pricereview_sign SET sign4 = NULL, sign_total = sign_total + 1 WHERE id = :id AND sign4 IS NOT NULL";
$stmt = $conn->prepare($sql_str);
$stmt->bindParam(':id', $sign['id']);
$stmt->execute();
echo $sign['mid'];
echo "<br>";
}
}
}

4
wms/mkt/assets/js/pricereviewAlpine.js

@ -1182,13 +1182,13 @@ const pricereviewCheck = ()=>{
totalStandardPrice(){
return this.totalElevatorsPrice() + this.otherOptionsTotalPrice() + this.optionsTotalPrice() + this.maintainOptionsTotalPrice() + this.demolishOptionsTotalPrice();
},
check(sign, status){
check(sign, status, user_id = this.user_id ){
console.log(sign);
const form = new FormData();
form.append('sign', sign);
form.append('mid', this.mid);
form.append('result', status);
form.append('user_id', this.user_id);
form.append('user_id', user_id);
form.append('reviewcomment', this.reviewcomment);
form.append('currentSignId', currentSignId);
form.append('token', token);

76
wms/mkt/exportTable.php

@ -0,0 +1,76 @@
<?php
require_once "./conn.php";
$sql_str = "SELECT pricereview_main.*, account.name AS person_name FROM pricereview_main
LEFT JOIN account ON account.accountid = pricereview_main.person
WHERE pricereview_main.status <> 'D'
AND pricereview_main.create_at >= '2024-01-01'
AND pricereview_main.create_at <= '2024-01-31'
AND ekind = '汰改'";
$stmt = $conn->prepare($sql_str);
// $stmt->bindParam(':vol_no', $vol_no);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>
<table border=1>
<tr>
<th>ID</th>
<th>卷號</th>
<th>營業員</th>
<th>客戶名稱</th>
<th>案件名稱</th>
<th>牌價總額</th>
<th>售價總額</th>
<th>價率</th>
<th>預定成交日</th>
<th>預定交期</th>
<th>建檔人</th>
<th>建檔時間</th>
<th>狀態</th>
</tr>
<?php foreach($result as $item): ?>
<tr>
<td><?php echo $item['id']; ?></td>
<td><?php echo $item['contractno']; ?></td>
<td><?php echo $item['person_name']; ?></td>
<td><?php echo $item['company']; ?></td>
<td><?php echo $item['case_name']; ?></td>
<td><?php echo $item['price_lowest']; ?></td>
<td><?php echo $item['price_total']; ?></td>
<td><?php echo ((int)$item['price_total'] / (int)$item['price_lowest'] * 100) ."%"; ?></td>
<td><?php echo $item['predeal_date']; ?></td>
<td><?php echo $item['facilitok_date']; ?></td>
<td><?php echo $item['creater']; ?></td>
<td><?php echo $item['create_at']; ?></td>
<td>
<?php
if($item['status'] == 'YY'){
echo "結案同意";
}elseif($item['status'] == 'YS'){
echo "簽核中";
}elseif($item['status'] == 'Y1'){
echo "暫存";
}elseif($item['status'] == 'YN'){
echo "結案不同意";
}else{
echo "---";
}
?>
</td>
</tr>
<?php endforeach; ?>
</table>
<script src="table2excel/dist/table2excel.min.js"></script>
<script>
const table2Excel = new Table2Excel('table') // new Table2Excel('table')
table2Excel.export('汰改價審明細', 'xlsx') // table2Excel.export('my-exported-table', 'xlsx')
</script>

69
wms/mkt/exportTable2.php

@ -0,0 +1,69 @@
<?php
require_once "./conn.php";
// $sql_str = "SELECT pricereview_main.*, account.name AS person_name FROM pricereview_main
// LEFT JOIN account ON account.accountid = pricereview_main.person
// WHERE pricereview_main.status <> 'D'
// AND pricereview_main.create_at >= '2024-01-01'
// AND pricereview_main.create_at <= '2024-01-31'
// AND ekind = '汰改'";
// $stmt = $conn->prepare($sql_str);
// // $stmt->bindParam(':vol_no', $vol_no);
// $stmt->execute();
// $result = $stmt->fetchAll(PDO::FETCH_ASSOC);
$sql_str = "SELECT con_maintance_examine_apply.*, account.name AS person_name, con_maintance_examine_clear.* FROM con_maintance_examine_apply
LEFT JOIN con_maintance_examine_clear ON con_maintance_examine_clear.apply_key = con_maintance_examine_apply.apply_key
LEFT JOIN account ON account.accountid = con_maintance_examine_apply.salesman
WHERE con_maintance_examine_apply.create_at >= '2024-01-01' AND con_maintance_examine_apply.create_at <= '2024-01-31'";
$stmt = $conn->prepare($sql_str);
// $stmt->bindParam(':vol_no', $vol_no);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>
<table border=1>
<tr>
<th>ID</th>
<th>卷號</th>
<th>營業員</th>
<th>客戶名稱</th>
<th>案件名稱</th>
<th>標準價</th>
<th>售價總額</th>
<th>契約成交價</th>
<th>保養月數</th>
<th>建檔人</th>
<th>建檔時間</th>
<th>狀態</th>
</tr>
<?php foreach($result as $key=>$item): ?>
<tr>
<td><?php echo $key+1; ?></td>
<td><?php echo $item['vol_no']; ?></td>
<td><?php echo $item['person_name']; ?></td>
<td><?php echo $item['customer']; ?></td>
<td><?php echo $item['case_name']; ?></td>
<td><?php echo $item['stand_price']; ?></td>
<td><?php echo $item['contract_price']; ?></td>
<td><?php echo $item['sold_price']; ?></td>
<td><?php echo $item['maintain_months'] . '月'; ?></td>
<td><?php echo $item['creater']; ?></td>
<td><?php echo $item['create_at']; ?></td>
<td>
簽核中
</td>
</tr>
<?php endforeach; ?>
</table>
<script src="table2excel/dist/table2excel.min.js"></script>
<script>
const table2Excel = new Table2Excel('table') // new Table2Excel('table')
table2Excel.export('保養價審', 'xlsx') // table2Excel.export('my-exported-table', 'xlsx')
</script>

32
wms/mkt/price_normal-index.php

@ -678,97 +678,97 @@ include "../header.php";
<td height=51 class=xl89 style='height:38.0pt;border-top:none'>MAP100-280*2-CO09</td>
<td class=xl109 style='border-top:none;border-left:none'>75.0 </td>
<td class=xl109 style='border-top:none;border-left:none'>3.0 </td>
<td class=xl110 style='border-top:none;border-left:none'>岩板;L型開門另加3萬元/</td>
<td class=xl110 style='border-top:none;border-left:none'>岩板;L型開門另加3萬元/</td>
</tr>
<tr height=51 style='mso-height-source:userset;height:38.0pt'>
<td height=51 class=xl89 style='height:38.0pt;border-top:none'>MAP100-280*3-CO09</td>
<td class=xl109 style='border-top:none;border-left:none'>86.5 </td>
<td class=xl109 style='border-top:none;border-left:none'>6.0 </td>
<td class=xl110 style='border-top:none;border-left:none'>岩板;L型開門另加3萬元/</td>
<td class=xl110 style='border-top:none;border-left:none'>岩板;L型開門另加3萬元/</td>
</tr>
<tr height=51 style='mso-height-source:userset;height:38.0pt'>
<td height=51 class=xl89 style='height:38.0pt;border-top:none'>MAP100-280*4-CO09</td>
<td class=xl109 style='border-top:none;border-left:none'>94.5 </td>
<td class=xl109 style='border-top:none;border-left:none'>9.0 </td>
<td class=xl110 style='border-top:none;border-left:none'>岩板;L型開門另加3萬元/</td>
<td class=xl110 style='border-top:none;border-left:none'>岩板;L型開門另加3萬元/</td>
</tr>
<tr height=51 style='mso-height-source:userset;height:38.0pt'>
<td height=51 class=xl89 style='height:38.0pt;border-top:none'>MAP100-280*5-CO09</td>
<td class=xl109 style='border-top:none;border-left:none'>102.5 </td>
<td class=xl109 style='border-top:none;border-left:none'>12.0 </td>
<td class=xl110 style='border-top:none;border-left:none'>岩板;L型開門另加3萬元/</td>
<td class=xl110 style='border-top:none;border-left:none'>岩板;L型開門另加3萬元/</td>
</tr>
<tr height=51 style='mso-height-source:userset;height:38.0pt'>
<td height=51 class=xl89 style='height:38.0pt;border-top:none'>MAP100-280*2-CO09</td>
<td class=xl109 style='border-top:none;border-left:none'>82.0 </td>
<td class=xl109 style='border-top:none;border-left:none'>3.0 </td>
<td class=xl110 style='border-top:none;border-left:none'>人造皮革;L型開門另加3萬元/</td>
<td class=xl110 style='border-top:none;border-left:none'>人造皮革;L型開門另加3萬元/</td>
</tr>
<tr height=51 style='mso-height-source:userset;height:38.0pt'>
<td height=51 class=xl89 style='height:38.0pt;border-top:none'>MAP100-280*3-CO09</td>
<td class=xl109 style='border-top:none;border-left:none'>90.0 </td>
<td class=xl109 style='border-top:none;border-left:none'>6.0 </td>
<td class=xl110 style='border-top:none;border-left:none'>人造皮革;L型開門另加3萬元/</td>
<td class=xl110 style='border-top:none;border-left:none'>人造皮革;L型開門另加3萬元/</td>
</tr>
<tr height=51 style='mso-height-source:userset;height:38.0pt'>
<td height=51 class=xl89 style='height:38.0pt;border-top:none'>MAP100-280*4-CO09</td>
<td class=xl109 style='border-top:none;border-left:none'>98.0 </td>
<td class=xl109 style='border-top:none;border-left:none'>9.0 </td>
<td class=xl110 style='border-top:none;border-left:none'>人造皮革;L型開門另加3萬元/</td>
<td class=xl110 style='border-top:none;border-left:none'>人造皮革;L型開門另加3萬元/</td>
</tr>
<tr class=xl66 height=51 style='mso-height-source:userset;height:38.0pt'>
<td height=51 class=xl89 style='height:38.0pt;border-top:none'>MAP100-280*5-CO09</td>
<td class=xl109 style='border-top:none;border-left:none'>107.0 </td>
<td class=xl109 style='border-top:none;border-left:none'>12.0 </td>
<td class=xl110 style='border-top:none;border-left:none'>人造皮革;L型開門另加3萬元/</td>
<td class=xl110 style='border-top:none;border-left:none'>人造皮革;L型開門另加3萬元/</td>
</tr>
<tr class=xl66 height=51 style='mso-height-source:userset;height:38.0pt'>
<td height=51 class=xl89 style='height:38.0pt;border-top:none'>MAP100-320*2-CO09</td>
<td class=xl109 style='border-top:none;border-left:none'>77.5 </td>
<td class=xl109 style='border-top:none;border-left:none'>3.0 </td>
<td class=xl110 style='border-top:none;border-left:none'>岩板;L型開門另加3萬元/</td>
<td class=xl110 style='border-top:none;border-left:none'>岩板;L型開門另加3萬元/</td>
</tr>
<tr class=xl66 height=51 style='mso-height-source:userset;height:38.0pt'>
<td height=51 class=xl89 style='height:38.0pt;border-top:none'>MAP100-320*3-CO09</td>
<td class=xl109 style='border-top:none;border-left:none'>88.5 </td>
<td class=xl109 style='border-top:none;border-left:none'>6.0 </td>
<td class=xl110 style='border-top:none;border-left:none'>岩板;L型開門另加3萬元/</td>
<td class=xl110 style='border-top:none;border-left:none'>岩板;L型開門另加3萬元/</td>
</tr>
<tr class=xl66 height=51 style='mso-height-source:userset;height:38.0pt'>
<td height=51 class=xl89 style='height:38.0pt;border-top:none'>MAP100-320*4-CO09</td>
<td class=xl109 style='border-top:none;border-left:none'>96.5 </td>
<td class=xl109 style='border-top:none;border-left:none'>9.0 </td>
<td class=xl110 style='border-top:none;border-left:none'>岩板;L型開門另加3萬元/</td>
<td class=xl110 style='border-top:none;border-left:none'>岩板;L型開門另加3萬元/</td>
</tr>
<tr class=xl66 height=51 style='mso-height-source:userset;height:38.0pt'>
<td height=51 class=xl89 style='height:38.0pt;border-top:none'>MAP100-320*5-CO09</td>
<td class=xl109 style='border-top:none;border-left:none'>106.0 </td>
<td class=xl109 style='border-top:none;border-left:none'>12.0 </td>
<td class=xl110 style='border-top:none;border-left:none'>岩板;L型開門另加3萬元/</td>
<td class=xl110 style='border-top:none;border-left:none'>岩板;L型開門另加3萬元/</td>
</tr>
<tr class=xl66 height=51 style='mso-height-source:userset;height:38.0pt'>
<td height=51 class=xl89 style='height:38.0pt;border-top:none'>MAP100-320*2-CO09</td>
<td class=xl109 style='border-top:none;border-left:none'>84.0 </td>
<td class=xl109 style='border-top:none;border-left:none'>3.0 </td>
<td class=xl110 style='border-top:none;border-left:none'>人造皮革;L型開門另加3萬元/</td>
<td class=xl110 style='border-top:none;border-left:none'>人造皮革;L型開門另加3萬元/</td>
</tr>
<tr class=xl66 height=51 style='mso-height-source:userset;height:38.0pt'>
<td height=51 class=xl89 style='height:38.0pt;border-top:none'>MAP100-320*3-CO09</td>
<td class=xl109 style='border-top:none;border-left:none'>92.0 </td>
<td class=xl109 style='border-top:none;border-left:none'>6.0 </td>
<td class=xl110 style='border-top:none;border-left:none'>人造皮革;L型開門另加3萬元/</td>
<td class=xl110 style='border-top:none;border-left:none'>人造皮革;L型開門另加3萬元/</td>
</tr>
<tr class=xl66 height=51 style='mso-height-source:userset;height:38.0pt'>
<td height=51 class=xl89 style='height:38.0pt;border-top:none'>MAP100-320*4-CO09</td>
<td class=xl109 style='border-top:none;border-left:none'>100.0 </td>
<td class=xl109 style='border-top:none;border-left:none'>9.0 </td>
<td class=xl110 style='border-top:none;border-left:none'>人造皮革;L型開門另加3萬元/</td>
<td class=xl110 style='border-top:none;border-left:none'>人造皮革;L型開門另加3萬元/</td>
</tr>
<tr class=xl66 height=51 style='mso-height-source:userset;height:38.0pt'>
<td height=51 class=xl89 style='height:38.0pt;border-top:none'>MAP100-320*5-CO09</td>
<td class=xl109 style='border-top:none;border-left:none'>108.0 </td>
<td class=xl109 style='border-top:none;border-left:none'>12.0 </td>
<td class=xl110 style='border-top:none;border-left:none'>人造皮革;L型開門另加3萬元/</td>
<td class=xl110 style='border-top:none;border-left:none'>人造皮革;L型開門另加3萬元/</td>
</tr>
<tr class=xl66 height=51 style='mso-height-source:userset;height:38.0pt'>
<td height=51 class=xl89 style='height:38.0pt;border-top:none'> </td>

8
wms/mkt/pricereview-index.php

@ -241,7 +241,8 @@ $para = "function_name=pricereview&" . $token_link;
$(function() {
$('#table_index2').DataTable({
"scrollX": true,
"pageLength": 50
"pageLength": 50,
displayLength: 10000,
});
/*
var api = $('#table_index').dataTable().api();
@ -715,7 +716,10 @@ if ($data) :
<a class="applybtn" href="../contract/contract-new-apply.php?id=<?php echo $data['id'] . '&' . $para; ?>">
<?php if ($data['applystatus'] < 1) {
echo "申請";
} else {
} elseif($data['applystatus'] == 2) {
echo "重新申請";
}
else {
echo "檢視";
} ?>
</a><br>

11
wms/mkt/pricereviewCheck.php

@ -618,7 +618,7 @@ function getSignerName($signer){
</td>
</tr>
<tr>
<td rowspan=3>材料</td>
<td rowspan=3>安裝</td>
<td>5.安裝完畢款</td>
<td><input type="text" class="form-control" x-model="pays[4].pay_scale" disabled /></td>
<td><input type="text" class="form-control" :value="Number(pays[4].pay_amount).toLocaleString()" disabled /></td>
@ -677,7 +677,7 @@ function getSignerName($signer){
</tr>
<tr>
<td colspan="2">備註</td>
<td colspan="3"><textarea name="" id="" cols="30" rows="5" class="form-control" disabled></textarea></td>
<td colspan="3"><textarea name="" id="" cols="30" rows="5" class="form-control" disabled x-model="pays[0].pay_note"></textarea></td>
</tr>
</tbody>
</table>
@ -763,8 +763,8 @@ function getSignerName($signer){
<table class="table" style="width:700px">
<thead>
<tr>
<th>審核</th>
<th>審核人</th>
<th style="width:150px">審核</th>
<th style="width:100px">審核人</th>
<th>結果</th>
<th>意見</th>
<th>時間</th>
@ -880,6 +880,9 @@ function getSignerName($signer){
<div>
<button class="btn btn-primary" @click="window.history.go(-1)">回上頁</button>
<?php if($contract['status'] == "YS"){ ?>
<?php if($currentSigner == "M0006" && $user_id == "M0060"): ?>
<button class="btn btn-primary" @click="check(<?php echo $currentSign; ?>, 'YN', 'M0006')">總經理權限(退回)</button>
<?php endif; ?>
<?php if($currentSigner == $user_id): ?>
<button class="btn btn-primary" @click="check(<?php echo $currentSign; ?>, 'YN')">不同意(退回)</button>
<?php if($sign1=='W' || ($sign1=='Y' && $sign2 =='W') || ($sign1 == 'Y' && ($sign2 == 'Y' || $sign2 == NULL) && $sign3 == 'W' && $sign4 == 'W')): ?>

6
wms/mkt/table2excel/.babelrc

@ -0,0 +1,6 @@
{
"presets":[
"es2015",
"stage-1"
]
}

58
wms/mkt/table2excel/.gitignore

@ -0,0 +1,58 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Typescript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env

192
wms/mkt/table2excel/README.md

@ -0,0 +1,192 @@
# Table2Excel.js
This is a library to export html tables to excel sheets.
## Precondition
It has to be a row * column table
## Features
1. able to export with width, alignment and colors
2. extendable
## Dependencies
[ExcelJS](https://github.com/guyonroche/exceljs)
[FileSaver.js](https://github.com/eligrey/FileSaver.js)
## Live Demo
[Demo](https://jackgit.github.io/table2excel.js/index.html)
## Include table2excel.js
### npm
`ExcelJS` is peer dependency to `table2excel.js`, so you need to install exceljs first:
```bash
npm i exceljs
```
then, install table2excel.js:
```bash
npm i table2excel.js
```
use in your code like:
```js
import Table2Excel from 'table2excel.js'
new Table2Excel('table').export()
```
you may also need a config in webpack:
```js
node: { fs: 'empty' }
```
### table2excel.min.js (with ExcelJS packed)
```html
<script src="path/to/table2excel.min.js"></script>
```
### table2excel.core.js (without ExcelJS packed)
```html
<script src="path/to/exceljs.min.js"></script>
<script src="path/to/table2excel.core.js"></script>
```
## Basic Usage
```js
const table2Excel = new Table2Excel(selector, options) // new Table2Excel('table')
table2Excel.export(fileName, extension) // table2Excel.export('my-exported-table', 'xlsx')
```
`extension` can be `'xls'` or `'xlsx'`, default as `'xlsx'`
### selector
It's optional, and defaulted as `'table'`
### options
It's optional, and defaulted as:
```js
{
workbook: {
views: [{
x: 0, y: 0, width: 10000, height: 20000,
firstSheet: 0, activeTab: 1, visibility: 'visible'
}]
},
widthRatio: .14,
plugins: [
Table2Excel.plugins.fontPlugin,
Table2Excel.plugins.fillPlugin,
Table2Excel.plugins.formPlugin,
Table2Excel.plugins.alignmentPlugin,
Table2Excel.plugins.hyperlinkPlugin,
Table2Excel.plugins.autoWidthPlugin
]
}
```
`workbook` is options used while creating a workbook, please refer [exceljs#create-a-workbook](https://github.com/guyonroche/exceljs#create-a-workbook) for details.
`widthRatio` is a ratio that will be used while converting `width` style of html table cells to width of sheet cells.
## Plugins
Plugin helps to extend the ability of transforming table to excel.
Build-in plugins can be access like:
```js
Table2Excel.plugins.fontPlugin,
Table2Excel.plugins.fillPlugin,
Table2Excel.plugins.formPlugin,
Table2Excel.plugins.alignmentPlugin,
Table2Excel.plugins.hyperlinkPlugin,
Table2Excel.plugins.autoWidthPlugin
```
A plugin can be defined to join different phase of table to excel process, and in different phase, plugin is able to access different objects from context.
```js
{
/**
* after an empty workbook created
* @param {ExcelJS.Workbook} context.workbook
* @param {NodeList} context.tables
*/
workbookCreated ({ workbook, tables }) {},
/**
* after an empty worksheet created
* @param {ExcelJS.Workbook} workbook
* @param {NodeList} tables
* @param {ExcelJS.Worksheet} worksheet
* @param {HTMLTableElement} table
*/
worksheetCreated ({ workbook, tables, worksheet, table }) {},
/**
* after a worksheet been filled with data from table
* @param {ExcelJS.Workbook} workbook
* @param {NodeList} tables
* @param {ExcelJS.Worksheet} worksheet
* @param {HTMLTableElement} table
*/
worksheetCompleted ({ workbook, tables, worksheet, table }) {},
/**
* after an cell of worksheet created
* @param {ExcelJS.Workbook} workbook
* @param {NodeList} tables
* @param {ExcelJS.Worksheet} worksheet
* @param {HTMLTableElement} table
* @param {ExcelJS.Cell} workcell
* @param {HTMLTableCellElement} cell
* @param {colRange} [from, to]
* @param {rowRange} [from, to]
*/
workcellCreated ({ workbook, tables, worksheet, table, workcell, cell, cellStyle, colRange, rowRange }) {}
}
```
Example 1, you can define a plugin to make some rows or columns hidden of exported excel:
```js
const table2Excel = new Table2Excel('table', {
plugins: [{
worksheetCompleted ({ workbook, tables, worksheet, table }) {
worksheet.getRow(1).hidden = true
worksheet.getColumn(1).hidden = true
}
}]
})
```
Example 2, you can add your customized cell parser for your table:
```js
const table2Excel = new Table2Excel('table', {
plugins: [{
workcellCreated ({ workbook, tables, worksheet, table, workcell, cell, cellStyle, rowRange, colRange }) {
workcell.value = { text: '', link: '' }
workcell.style = {
...workcell.style,
font: {},
color: {}
}
}
}]
})
```

2
wms/mkt/table2excel/dist/table2excel.core.js

File diff suppressed because one or more lines are too long

18
wms/mkt/table2excel/dist/table2excel.min.js

File diff suppressed because one or more lines are too long

1123
wms/mkt/table2excel/docs/index.html

File diff suppressed because it is too large

17
wms/mkt/table2excel/docs/js/exceljs.min.js

File diff suppressed because one or more lines are too long

2
wms/mkt/table2excel/docs/js/table2excel.core.js

File diff suppressed because one or more lines are too long

11
wms/mkt/table2excel/es5/constants.js

@ -0,0 +1,11 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var MIME_TYPES = exports.MIME_TYPES = {
xls: 'application/vnd.ms-excel',
xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
};
var WIDTH_RATIO = exports.WIDTH_RATIO = .14;

26
wms/mkt/table2excel/es5/index.js

@ -0,0 +1,26 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _table2excel = require('./table2excel');
var _table2excel2 = _interopRequireDefault(_table2excel);
var _plugins = require('./plugins');
var _plugins2 = _interopRequireDefault(_plugins);
var _utils = require('./utils');
var utils = _interopRequireWildcard(_utils);
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
_table2excel2.default.plugins = _plugins2.default;
_table2excel2.default.utils = utils;
exports.default = _table2excel2.default;

62
wms/mkt/table2excel/es5/plugins/alignment.js

@ -0,0 +1,62 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
/**
* '-webkit-right' -> 'right'
* 'right' -> 'right'
* etc...
*/
var getHorizontalAlign = function getHorizontalAlign() {
var value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
var aligns = ['right', 'left', 'center', 'justify'];
for (var i = 0; i < aligns.length; i++) {
if (value.includes(aligns[i])) {
return aligns[i];
}
}
};
/**
* 'baseline' -> 'middle'
* 'text-top' -> 'top'
* 'text-bottom' -> 'bottom'
* 'sub' -> 'top'
* 'super' -> 'bottom'
*/
var getVerticalAlign = function getVerticalAlign() {
var value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
var aligns = ['top', 'middle', 'bottom'];
for (var i = 0; i < aligns.length; i++) {
if (value.includes(aligns[i])) {
return aligns[i];
}
}
var mapping = {
'baseline': 'middle',
'super': 'top',
'sub': 'bottom'
};
return mapping[value];
};
exports.default = {
workcellCreated: function workcellCreated(_ref) {
var workcell = _ref.workcell,
cellStyle = _ref.cellStyle;
var verticalAlign = cellStyle.verticalAlign,
textAlign = cellStyle.textAlign;
workcell.alignment = _extends({}, workcell.alignment || {}, {
vertical: getVerticalAlign(verticalAlign),
horizontal: getHorizontalAlign(textAlign)
});
}
};

17
wms/mkt/table2excel/es5/plugins/autoWidth.js

@ -0,0 +1,17 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = {
workcellCreated: function workcellCreated(_ref) {
var worksheet = _ref.worksheet,
colRange = _ref.colRange,
cell = _ref.cell,
cellStyle = _ref.cellStyle;
if (colRange.from === colRange.to && cellStyle.width !== 'auto') {
worksheet.getColumn(colRange.from + 1).width = +cellStyle.width.split('px')[0] * this.options.widthRatio;
}
}
};

32
wms/mkt/table2excel/es5/plugins/fill.js

@ -0,0 +1,32 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _utils = require('../utils');
exports.default = {
workcellCreated: function workcellCreated(_ref) {
var workcell = _ref.workcell,
cellStyle = _ref.cellStyle;
var color = (0, _utils.argb)(cellStyle.backgroundColor);
if (color === '00000000') {
// background is transparent, equals none pattern fill
workcell.fill = _extends({}, workcell.fill || {}, {
type: 'pattern',
pattern: 'none'
});
} else {
workcell.fill = _extends({}, workcell.fill || {}, {
type: 'pattern',
pattern: 'solid',
fgColor: { argb: color }
});
}
}
};

24
wms/mkt/table2excel/es5/plugins/font.js

@ -0,0 +1,24 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _utils = require('../utils');
exports.default = {
workcellCreated: function workcellCreated(_ref) {
var workcell = _ref.workcell,
cellStyle = _ref.cellStyle;
var fontWeight = cellStyle.fontWeight;
workcell.font = _extends({}, workcell.font || {}, {
name: cellStyle.fontFamily,
color: { argb: (0, _utils.argb)(cellStyle.color) },
bold: fontWeight === 'bold' || +fontWeight > 600 ? true : false
});
}
};

16
wms/mkt/table2excel/es5/plugins/form.js

@ -0,0 +1,16 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = {
workcellCreated: function workcellCreated(_ref) {
var workcell = _ref.workcell,
cell = _ref.cell;
var child = cell.children[0];
if (child && ['INPUT', 'SELECT', 'TEXTAREA'].includes(child.tagName)) {
workcell.value = child.value;
}
}
};

16
wms/mkt/table2excel/es5/plugins/hyperlink.js

@ -0,0 +1,16 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = {
workcellCreated: function workcellCreated(_ref) {
var workcell = _ref.workcell,
cell = _ref.cell;
var child = cell.children[0];
if (child && child.tagName === 'A') {
workcell.value = { text: child.innerText, hyperlink: child.href };
}
}
};

40
wms/mkt/table2excel/es5/plugins/index.js

@ -0,0 +1,40 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _font = require('./font');
var _font2 = _interopRequireDefault(_font);
var _fill = require('./fill');
var _fill2 = _interopRequireDefault(_fill);
var _form = require('./form');
var _form2 = _interopRequireDefault(_form);
var _alignment = require('./alignment');
var _alignment2 = _interopRequireDefault(_alignment);
var _hyperlink = require('./hyperlink');
var _hyperlink2 = _interopRequireDefault(_hyperlink);
var _autoWidth = require('./autoWidth');
var _autoWidth2 = _interopRequireDefault(_autoWidth);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
exports.default = {
fontPlugin: _font2.default,
fillPlugin: _fill2.default,
formPlugin: _form2.default,
alignmentPlugin: _alignment2.default,
hyperlinkPlugin: _hyperlink2.default,
autoWidthPlugin: _autoWidth2.default
};

202
wms/mkt/table2excel/es5/table2excel.js

@ -0,0 +1,202 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _exceljs = require('exceljs/dist/es5/exceljs.browser');
var _exceljs2 = _interopRequireDefault(_exceljs);
var _utils = require('./utils');
var _constants = require('./constants');
var _plugins = require('./plugins');
var _plugins2 = _interopRequireDefault(_plugins);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
var PLUGIN_FUNCS = ['workbookCreated', 'worksheetCreated', 'worksheetCompleted', 'workcellCreated'];
var DEFAULT_WORKBOOK_OPTIONS = {
views: [{
x: 0, y: 0, width: 10000, height: 20000,
firstSheet: 0, activeTab: 1, visibility: 'visible'
}]
};
var DEFAULT_OPTIONS = {
workbook: DEFAULT_WORKBOOK_OPTIONS,
widthRatio: _constants.WIDTH_RATIO,
plugins: [].concat(_toConsumableArray(Object.values(_plugins2.default)))
};
var Table2Excel = function () {
function Table2Excel() {
var _this = this;
var selector = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'table';
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
_classCallCheck(this, Table2Excel);
this.tables = Array.from(typeof selector === 'string' ? document.querySelectorAll(selector) : selector);
this.options = Object.assign({}, DEFAULT_OPTIONS, options);
this.plugins = {};
PLUGIN_FUNCS.forEach(function (funName) {
_this.plugins[funName] = _this.options.plugins.filter(function (plugin) {
return plugin[funName];
}).map(function (plugin) {
return plugin[funName];
});
});
this.pluginContext = {};
}
_createClass(Table2Excel, [{
key: '_invokePlugin',
value: function _invokePlugin(func) {
var _this2 = this;
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
this.pluginContext = Object.assign({}, this.pluginContext, context);
this.plugins[func].forEach(function (handler) {
return handler.call(_this2, _this2.pluginContext);
});
}
}, {
key: 'toExcel',
value: function toExcel() {
var _this3 = this;
var tables = this.tables,
options = this.options;
var workbook = new _exceljs2.default.Workbook(); // create workbook
Object.assign(workbook, options);
// workbookCreated plugins
this._invokePlugin('workbookCreated', { workbook: workbook, tables: tables });
tables.forEach(function (table, index) {
var worksheet = workbook.addWorksheet('Sheet ' + (index + 1));
// worksheetCreated plugins
_this3._invokePlugin('worksheetCreated', { worksheet: worksheet, table: table });
_this3.toSheet(table, worksheet);
// worksheetCompleted plugins
_this3._invokePlugin('worksheetCompleted', { worksheet: worksheet, table: table });
});
return this.workbook = workbook;
}
}, {
key: 'toSheet',
value: function toSheet(table, worksheet) {
var _this4 = this;
// get total cols and rows
var totalRows = table.rows.length;
var totalCols = 0;
if (table.rows.length > 0) {
for (var i = 0; i < table.rows[0].cells.length; i++) {
totalCols += table.rows[0].cells[i].colSpan;
}
}
var cells = [];
Array.from(table.rows).forEach(function (row) {
Array.from(row.cells).forEach(function (cell) {
cells.push({
rowRange: {},
colRange: {},
el: cell
});
});
});
// create matrix
var helperMatrix = [];
for (var r = 0; r < totalRows; r++) {
var row = [];
for (var c = 0; c < totalCols; c++) {
row.push({ cell: null });
}
helperMatrix.push(row);
}
// mark matrix
var cursor = 0;
for (var _r = 0; _r < totalRows; _r++) {
for (var _c = 0; _c < totalCols; _c++) {
// skip if current matrix unit is already assigned
if (helperMatrix[_r][_c].cell) {
continue;
}
// assign cell to current matrix unit
var cell = cells[cursor++];
var _cell$el = cell.el,
rowSpan = _cell$el.rowSpan,
colSpan = _cell$el.colSpan;
cell.rowRange = { from: _r, to: _r };
cell.colRange = { from: _c, to: _c };
for (var y = _r; y < _r + rowSpan; y++) {
for (var x = _c; x < _c + colSpan; x++) {
helperMatrix[y][x].cell = cell;
cell.colRange.to = x;
cell.rowRange.to = y;
}
}
}
}
// read matrix to sheet
cells.forEach(function (cell) {
var rowRange = cell.rowRange,
colRange = cell.colRange,
el = cell.el;
var innerText = el.innerText;
var workcell = (0, _utils.mergeCells)(worksheet, colRange.from, rowRange.from, colRange.to, rowRange.to);
var cellStyle = getComputedStyle(el);
workcell.value = innerText;
// workcellCreated
_this4._invokePlugin('workcellCreated', { workcell: workcell, cell: el, rowRange: rowRange, colRange: colRange, cellStyle: cellStyle });
});
}
}, {
key: 'export',
value: function _export(fileName, ext) {
if (!this.workbook) {
this.toExcel();
}
(0, _utils.saveAsExcel)(this.workbook, fileName, ext);
}
}]);
return Table2Excel;
}();
exports.default = Table2Excel;

89
wms/mkt/table2excel/es5/utils.js

@ -0,0 +1,89 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.argb = exports.mergeCells = exports.cellPosition = exports.columnIndex = exports.saveAsExcel = undefined;
var _constants = require('./constants');
var _fileSaver = require('file-saver');
var saveAsExcel = exports.saveAsExcel = function saveAsExcel(workbook) {
var filename = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'table';
var ext = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'xlsx';
var type = _constants.MIME_TYPES[ext];
if (!type) {
console.error(ext + ' file extension is not supported');
return;
}
workbook.xlsx.writeBuffer().then(function (uint8) {
(0, _fileSaver.saveAs)(new Blob([uint8.buffer], { type: type }), filename + '.' + ext);
});
};
var letter = function letter(num) {
var a = 'A'.charCodeAt(0);
return String.fromCharCode(a + num - 1);
};
/**
* 0 => A
* 25 => Z
* 26 => AA
*/
var columnIndex = exports.columnIndex = function columnIndex(num) {
var result = void 0;
num = num + 1;
if (num <= 26) {
result = letter(num);
} else {
var mod = num % 26;
var quotient = Math.floor(num / 26);
if (mod === 0) {
result = letter(quotient - 1) + letter(26);
} else {
result = letter(quotient) + letter(mod);
}
}
return result;
};
// x = 0, y = 0 => 'A1'
// x = 0, y = 1 => 'A2'
// x = 1, y = 0 => 'B1'
var cellPosition = exports.cellPosition = function cellPosition(x, y) {
return '' + columnIndex(x) + (y + 1);
};
var mergeCells = exports.mergeCells = function mergeCells(sheet, x1, y1, x2, y2) {
var fromCell = cellPosition(x1, y1);
var toCell = cellPosition(x2, y2);
sheet.mergeCells(fromCell, toCell);
return sheet.getCell(fromCell);
};
/**
* convert rgb(0,0,0) rgba(0,0,0,0) to argb: FF00FF00
*/
var argb = exports.argb = function argb(color) {
var values = color.split('(')[1].split(')')[0].split(',').map(function (v, i) {
return i === 3 ? v * 255 : v;
});
if (values.length === 3) {
values.push(255);
}
values.unshift(values.pop());
return values.map(function (v) {
var s = parseInt(v).toString(16);
return s.length === 1 ? '0' + s : s;
}).join('').toUpperCase();
};

42
wms/mkt/table2excel/package.json

@ -0,0 +1,42 @@
{
"name": "table2excel.js",
"version": "1.0.0",
"description": "",
"main": "es5/index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --config webpack.core.config.js -p && webpack --config webpack.umd.config.js -p",
"build:es5": "babel src --out-dir es5"
},
"repository": {
"type": "git",
"url": "git+https://github.com/jackgit/table2excel.js.git"
},
"keywords": [
"table",
"js",
"excel",
"xlsx",
"xls"
],
"author": "ygjack414@hotmail.com",
"license": "MIT",
"bugs": {
"url": "https://github.com/jackgit/table2excel.js/issues"
},
"homepage": "https://github.com/jackgit/table2excel.js#readme",
"dependencies": {
"file-saver": "^1.3.3"
},
"peerDependencies": {
"exceljs": "^0.6.2"
},
"devDependencies": {
"babel-cli": "^6.26.0",
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-preset-es2015": "^6.24.1",
"babel-preset-stage-1": "^6.24.1",
"cross-env": "^5.2.0"
}
}

6
wms/mkt/table2excel/src/constants.js

@ -0,0 +1,6 @@
export const MIME_TYPES = {
xls: 'application/vnd.ms-excel',
xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
}
export const WIDTH_RATIO = .14

8
wms/mkt/table2excel/src/index.js

@ -0,0 +1,8 @@
import Table2Excel from './table2excel'
import plugins from './plugins'
import * as utils from './utils'
Table2Excel.plugins = plugins
Table2Excel.utils = utils
export default Table2Excel

49
wms/mkt/table2excel/src/plugins/alignment.js

@ -0,0 +1,49 @@
/**
* '-webkit-right' -> 'right'
* 'right' -> 'right'
* etc...
*/
const getHorizontalAlign = (value = '') => {
const aligns = ['right', 'left', 'center', 'justify']
for (let i = 0; i < aligns.length; i++) {
if (value.includes(aligns[i])) {
return aligns[i]
}
}
}
/**
* 'baseline' -> 'middle'
* 'text-top' -> 'top'
* 'text-bottom' -> 'bottom'
* 'sub' -> 'top'
* 'super' -> 'bottom'
*/
const getVerticalAlign = (value = '') => {
const aligns = ['top', 'middle', 'bottom']
for (let i = 0; i < aligns.length; i++) {
if (value.includes(aligns[i])) {
return aligns[i]
}
}
const mapping = {
'baseline': 'middle',
'super': 'top',
'sub': 'bottom'
}
return mapping[value]
}
export default {
workcellCreated ({ workcell, cellStyle }) {
const { verticalAlign, textAlign } = cellStyle
workcell.alignment = {
...(workcell.alignment || {}),
...({
vertical: getVerticalAlign(verticalAlign),
horizontal: getHorizontalAlign(textAlign)
})
}
}
}

7
wms/mkt/table2excel/src/plugins/autoWidth.js

@ -0,0 +1,7 @@
export default {
workcellCreated ({ worksheet, colRange, cell, cellStyle }) {
if (colRange.from === colRange.to && cellStyle.width !== 'auto') {
worksheet.getColumn(colRange.from + 1).width = (+cellStyle.width.split('px')[0]) * this.options.widthRatio
}
}
}

27
wms/mkt/table2excel/src/plugins/fill.js

@ -0,0 +1,27 @@
import { argb } from '../utils'
export default {
workcellCreated ({ workcell, cellStyle }) {
const color = argb(cellStyle.backgroundColor)
if (color === '00000000') {
// background is transparent, equals none pattern fill
workcell.fill = {
...(workcell.fill || {}),
...({
type: 'pattern',
pattern: 'none'
})
}
} else {
workcell.fill = {
...(workcell.fill || {}),
...({
type: 'pattern',
pattern: 'solid',
fgColor: { argb: color }
})
}
}
}
}

16
wms/mkt/table2excel/src/plugins/font.js

@ -0,0 +1,16 @@
import { argb } from '../utils'
export default {
workcellCreated ({ workcell, cellStyle }) {
const fontWeight = cellStyle.fontWeight
workcell.font = {
...(workcell.font || {}),
...({
name: cellStyle.fontFamily,
color: { argb: argb(cellStyle.color) },
bold: (fontWeight === 'bold' || +fontWeight > 600) ? true : false
})
}
}
}

8
wms/mkt/table2excel/src/plugins/form.js

@ -0,0 +1,8 @@
export default {
workcellCreated ({ workcell, cell }) {
const child = cell.children[0]
if (child && ['INPUT', 'SELECT', 'TEXTAREA'].includes(child.tagName)) {
workcell.value = child.value
}
}
}

8
wms/mkt/table2excel/src/plugins/hyperlink.js

@ -0,0 +1,8 @@
export default {
workcellCreated ({ workcell, cell }) {
const child = cell.children[0]
if (child && child.tagName === 'A') {
workcell.value = { text: child.innerText, hyperlink: child.href }
}
}
}

15
wms/mkt/table2excel/src/plugins/index.js

@ -0,0 +1,15 @@
import fontPlugin from './font'
import fillPlugin from './fill'
import formPlugin from './form'
import alignmentPlugin from './alignment'
import hyperlinkPlugin from './hyperlink'
import autoWidthPlugin from './autoWidth'
export default {
fontPlugin,
fillPlugin,
formPlugin,
alignmentPlugin,
hyperlinkPlugin,
autoWidthPlugin
}

149
wms/mkt/table2excel/src/table2excel.js

@ -0,0 +1,149 @@
import ExcelJS from 'exceljs/dist/es5/exceljs.browser'
import { mergeCells, saveAsExcel } from './utils'
import { WIDTH_RATIO } from './constants'
import plugins from './plugins'
const PLUGIN_FUNCS = ['workbookCreated', 'worksheetCreated', 'worksheetCompleted', 'workcellCreated']
const DEFAULT_WORKBOOK_OPTIONS = {
views: [{
x: 0, y: 0, width: 10000, height: 20000,
firstSheet: 0, activeTab: 1, visibility: 'visible'
}]
}
const DEFAULT_OPTIONS = {
workbook: DEFAULT_WORKBOOK_OPTIONS,
widthRatio: WIDTH_RATIO,
plugins: [...Object.values(plugins)]
}
export default class Table2Excel {
constructor (selector = 'table', options = {}) {
this.tables = Array.from(
typeof selector === 'string'
? document.querySelectorAll(selector)
: selector
)
this.options = Object.assign({}, DEFAULT_OPTIONS, options)
this.plugins = {}
PLUGIN_FUNCS.forEach(funName => {
this.plugins[funName] = this.options.plugins.filter(plugin => plugin[funName]).map(plugin => plugin[funName])
})
this.pluginContext = {}
}
_invokePlugin (func, context = {}) {
this.pluginContext = Object.assign({}, this.pluginContext, context)
this.plugins[func].forEach(handler => handler.call(this, this.pluginContext))
}
toExcel () {
const { tables, options } = this
const workbook = new ExcelJS.Workbook() // create workbook
Object.assign(workbook, options)
// workbookCreated plugins
this._invokePlugin('workbookCreated', { workbook, tables })
tables.forEach((table, index) => {
const worksheet = workbook.addWorksheet(`Sheet ${index + 1}`)
// worksheetCreated plugins
this._invokePlugin('worksheetCreated', { worksheet, table })
this.toSheet(table, worksheet)
// worksheetCompleted plugins
this._invokePlugin('worksheetCompleted', { worksheet, table })
})
return this.workbook = workbook
}
toSheet (table, worksheet) {
// get total cols and rows
const totalRows = table.rows.length
let totalCols = 0
if (table.rows.length > 0) {
for (let i = 0; i < table.rows[0].cells.length; i++) {
totalCols += table.rows[0].cells[i].colSpan
}
}
const cells = []
Array.from(table.rows).forEach(row => {
Array.from(row.cells).forEach(cell => {
cells.push({
rowRange: {},
colRange: {},
el: cell
})
})
})
// create matrix
const helperMatrix = []
for (let r = 0; r < totalRows; r++) {
const row = []
for (let c = 0; c < totalCols; c++) {
row.push({ cell: null })
}
helperMatrix.push(row)
}
// mark matrix
let cursor = 0
for (let r = 0; r < totalRows; r++) {
for (let c = 0; c < totalCols; c++) {
// skip if current matrix unit is already assigned
if (helperMatrix[r][c].cell) {
continue
}
// assign cell to current matrix unit
const cell = cells[cursor++]
const { rowSpan, colSpan } = cell.el
cell.rowRange = { from: r, to: r }
cell.colRange = { from: c, to: c }
for (let y = r; y < r + rowSpan; y++) {
for (let x = c; x < c + colSpan; x++) {
helperMatrix[y][x].cell = cell
cell.colRange.to = x
cell.rowRange.to = y
}
}
}
}
// read matrix to sheet
cells.forEach(cell => {
const { rowRange, colRange, el } = cell
const { innerText } = el
const workcell = mergeCells(worksheet, colRange.from, rowRange.from, colRange.to, rowRange.to)
const cellStyle = getComputedStyle(el)
workcell.value = innerText
// workcellCreated
this._invokePlugin('workcellCreated', { workcell, cell: el, rowRange, colRange, cellStyle })
})
}
export (fileName, ext) {
if (!this.workbook) {
this.toExcel()
}
saveAsExcel(this.workbook, fileName, ext)
}
}

81
wms/mkt/table2excel/src/utils.js

@ -0,0 +1,81 @@
import { MIME_TYPES } from './constants'
import { saveAs } from 'file-saver'
export const saveAsExcel = (workbook, filename = 'table', ext = 'xlsx') => {
const type = MIME_TYPES[ext]
if (!type) {
console.error(`${ext} file extension is not supported`)
return
}
workbook.xlsx.writeBuffer().then(uint8 => {
saveAs(
new Blob([uint8.buffer], { type }),
`${filename}.${ext}`
)
})
}
const letter = num => {
const a = 'A'.charCodeAt(0)
return String.fromCharCode(a + num - 1)
}
/**
* 0 => A
* 25 => Z
* 26 => AA
*/
export const columnIndex = num => {
let result
num = num + 1
if (num <= 26) {
result = letter(num)
} else {
const mod = num % 26
const quotient = Math.floor(num / 26)
if (mod === 0) {
result = letter(quotient - 1) + letter(26)
} else {
result = letter(quotient) + letter(mod)
}
}
return result
}
// x = 0, y = 0 => 'A1'
// x = 0, y = 1 => 'A2'
// x = 1, y = 0 => 'B1'
export const cellPosition = (x, y) => {
return `${columnIndex(x)}${y + 1}`
}
export const mergeCells = (sheet, x1, y1, x2, y2) => {
const fromCell = cellPosition(x1, y1)
const toCell = cellPosition(x2, y2)
sheet.mergeCells(fromCell, toCell)
return sheet.getCell(fromCell)
}
/**
* convert rgb(0,0,0) rgba(0,0,0,0) to argb: FF00FF00
*/
export const argb = color => {
const values = color
.split('(')[1].split(')')[0].split(',')
.map((v, i) => i === 3 ? v * 255 : v)
if (values.length === 3) {
values.push(255)
}
values.unshift(values.pop())
return values.map(v => {
const s = parseInt(v).toString(16)
return s.length === 1 ? `0${s}` : s
}).join('').toUpperCase()
}

26
wms/mkt/table2excel/webpack.core.config.js

@ -0,0 +1,26 @@
module.exports = {
entry: './src/index.js',
output: {
filename: './dist/table2excel.core.js',
library: 'Table2Excel',
libraryTarget: 'umd',
libraryExport: 'default'
},
module: {
rules: [
{
test: /\.js$/,
use: [
'babel-loader',
],
exclude: /node_modules/
}
]
},
externals: {
'exceljs/dist/es5/exceljs.browser': 'ExcelJS'
},
node: {
fs: 'empty'
}
};

23
wms/mkt/table2excel/webpack.umd.config.js

@ -0,0 +1,23 @@
module.exports = {
entry: './src/index.js',
output: {
filename: './dist/table2excel.min.js',
library: 'Table2Excel',
libraryTarget: 'umd',
libraryExport: 'default'
},
module: {
rules: [
{
test: /\.js$/,
use: [
'babel-loader',
],
exclude: /node_modules/
}
]
},
node: {
fs: 'empty'
}
};
Loading…
Cancel
Save