From bfb6b1df256df56c7a387682ffdf8feb3897bbb1 Mon Sep 17 00:00:00 2001
From: Junjie <fallin.jie@qq.com>
Date: 星期四, 31 八月 2023 10:48:34 +0800
Subject: [PATCH] #

---
 src/main/java/com/zy/crm/manager/entity/Contract.java                       |  271 ++++++
 src/main/java/com/zy/crm/manager/mapper/ContractMapper.java                 |   12 
 src/main/java/com/zy/crm/manager/utils/WordUtils.java                       |  175 ++++
 src/main/java/com/zy/crm/manager/mapper/ContractSalesMapper.java            |   16 
 src/main/resources/contractTemplate/jcxm_1.docx                             |    0 
 src/main/java/com/zy/crm/manager/controller/ContractController.java         |  296 +++++++
 src/main/java/com/zy/crm/manager/entity/ContractSales.java                  |   89 ++
 src/main/resources/mapper/ContractSalesMapper.xml                           |   23 
 src/main/webapp/views/contractSales/contractSales.html                      |  127 +++
 src/main/java/com/zy/crm/manager/service/ContractService.java               |    8 
 src/main/java/com/zy/crm/manager/utils/ChineseNumberUtils.java              |  111 ++
 src/main/resources/contractTemplate/upload/lock                             |    0 
 src/main/webapp/views/contract/contract.html                                |  236 +++++
 src/main/webapp/static/js/contractSales/contractSales.js                    |  262 ++++++
 src/main/java/com/zy/crm/manager/service/ContractSalesService.java          |   12 
 src/main/java/com/zy/crm/manager/service/impl/ContractServiceImpl.java      |   12 
 src/main/resources/mapper/ContractMapper.xml                                |   33 
 src/main/webapp/static/js/contract/contract.js                              |  431 ++++++++++
 src/main/java/com/zy/crm/manager/controller/ContractSalesController.java    |  135 +++
 src/main/java/com/zy/crm/manager/controller/WordController.java             |  155 +++
 src/main/java/com/zy/crm/manager/service/impl/ContractSalesServiceImpl.java |   18 
 src/main/resources/contractTemplate/zjxm_1.docx                             |    0 
 22 files changed, 2,422 insertions(+), 0 deletions(-)

diff --git a/src/main/java/com/zy/crm/manager/controller/ContractController.java b/src/main/java/com/zy/crm/manager/controller/ContractController.java
new file mode 100644
index 0000000..93fca31
--- /dev/null
+++ b/src/main/java/com/zy/crm/manager/controller/ContractController.java
@@ -0,0 +1,296 @@
+package com.zy.crm.manager.controller;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.mapper.EntityWrapper;
+import com.baomidou.mybatisplus.mapper.Wrapper;
+import com.baomidou.mybatisplus.plugins.Page;
+import com.core.common.DateUtils;
+import com.zy.crm.common.service.OssService;
+import com.zy.crm.manager.entity.Contract;
+import com.zy.crm.manager.entity.ContractSales;
+import com.zy.crm.manager.entity.PriOnline;
+import com.zy.crm.manager.service.ContractSalesService;
+import com.zy.crm.manager.service.ContractService;
+import com.core.annotations.ManagerAuth;
+import com.core.common.BaseRes;
+import com.core.common.Cools;
+import com.core.common.R;
+import com.core.domain.KeyValueVo;
+import com.zy.crm.common.web.BaseController;
+import com.zy.crm.manager.utils.ChineseNumberUtils;
+import com.zy.crm.manager.utils.WordUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.io.InputStreamResource;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.util.ClassUtils;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+@RestController
+public class ContractController extends BaseController {
+
+    @Autowired
+    private ContractService contractService;
+    @Autowired
+    private ContractSalesService contractSalesService;
+    @Autowired
+    private OssService ossService;
+
+    @RequestMapping(value = "/contract/{id}/auth")
+    @ManagerAuth
+    public R get(@PathVariable("id") String id) {
+        return R.ok(contractService.selectById(String.valueOf(id)));
+    }
+
+    @RequestMapping(value = "/contract/list/auth")
+    @ManagerAuth
+    public R list(@RequestParam(defaultValue = "1")Integer curr,
+                  @RequestParam(defaultValue = "10")Integer limit,
+                  @RequestParam(required = false)String orderByField,
+                  @RequestParam(required = false)String orderByType,
+                  @RequestParam(required = false)String condition,
+                  @RequestParam Map<String, Object> param){
+        EntityWrapper<Contract> wrapper = new EntityWrapper<>();
+        excludeTrash(param);
+        convert(param, wrapper);
+        allLike(Contract.class, param.keySet(), wrapper, condition);
+        if (!Cools.isEmpty(orderByField)){wrapper.orderBy(humpToLine(orderByField), "asc".equals(orderByType));}
+        return R.ok(contractService.selectPage(new Page<>(curr, limit), wrapper));
+    }
+
+    private <T> void convert(Map<String, Object> map, EntityWrapper<T> wrapper){
+        for (Map.Entry<String, Object> entry : map.entrySet()){
+            String val = String.valueOf(entry.getValue());
+            if (val.contains(RANGE_TIME_LINK)){
+                String[] dates = val.split(RANGE_TIME_LINK);
+                wrapper.ge(entry.getKey(), DateUtils.convert(dates[0]));
+                wrapper.le(entry.getKey(), DateUtils.convert(dates[1]));
+            } else {
+                wrapper.like(entry.getKey(), val);
+            }
+        }
+    }
+
+    @RequestMapping(value = "/contract/add/auth")
+    @ManagerAuth
+    public R add(Contract contract) {
+        contract.setCreateBy(getUserId());
+        contract.setCreateTime(new Date());
+        contractService.insert(contract);
+        return R.ok();
+    }
+
+	@RequestMapping(value = "/contract/update/auth")
+	@ManagerAuth
+    public R update(Contract contract){
+        if (Cools.isEmpty(contract) || null==contract.getId()){
+            return R.error();
+        }
+        contract.setUpdateBy(getUserId());
+        contract.setUpdateTime(new Date());
+        contractService.updateById(contract);
+        return R.ok();
+    }
+
+    @RequestMapping(value = "/contract/delete/auth")
+    @ManagerAuth
+    public R delete(@RequestParam(value="ids[]") Long[] ids){
+         for (Long id : ids){
+            contractService.deleteById(id);
+        }
+        return R.ok();
+    }
+
+    @RequestMapping(value = "/contract/generate/auth")
+    @ManagerAuth
+    public ResponseEntity<InputStreamResource> generate(@RequestParam Integer id,
+                                                        @RequestParam String contractTemplate){
+        try {
+            /////////////////////////鐢熸垚鍚堝悓鏁版嵁/////////////////////////
+            Contract contract = contractService.selectById(id);
+            if (contract == null) {
+                return null;
+            }
+            HashMap<String, Object> map = new HashMap<>();
+            map.put("{{customer}}", contract.getCustomer());
+            map.put("{{address}}", contract.getAddress());
+            map.put("{{company}}", contract.getCompany());
+            map.put("{{companyAddress}}", contract.getCompanyAddress());
+            map.put("{{taxNum}}", contract.getTaxNum());
+            map.put("{{bank}}", contract.getBank());
+            map.put("{{bankNum}}", contract.getBankNum());
+            map.put("{{city}}", contract.getCity());
+            map.put("{{shippingAddress}}", contract.getShippingAddress());
+            map.put("{{shippingName}}", contract.getShippingName());
+            map.put("{{shippingPhone}}", contract.getShippingPhone());
+            map.put("{{email}}", contract.getEmail());
+            map.put("{{boss}}", contract.getBoss());
+            map.put("{{priceChinese}}", ChineseNumberUtils.numberToChinese(contract.getPrice()));
+            map.put("{{priceSci}}", WordUtils.formatNumberForAccounting(contract.getPrice()));
+
+            SimpleDateFormat format = new SimpleDateFormat("yyyy骞碝M鏈坉d鏃�");
+            map.put("{{now}}", format.format(new Date()));
+            /////////////////////////鐢熸垚鍚堝悓鏁版嵁/////////////////////////
+
+            /////////////////////////鐢熸垚Tab琛ㄦ牸鏁版嵁/////////////////////////
+            List<ContractSales> contractSales = contractSalesService.selectByContractId(contract.getId());
+            List<List<String>> tabParam = new ArrayList<>();
+            ArrayList<String> tabTitle = new ArrayList<>();
+            tabTitle.add("搴忓彿");
+            tabTitle.add("鍝佸悕");
+            tabTitle.add("鏁伴噺");
+            tabTitle.add("鍗曚綅");
+            tabTitle.add("鍗曚环(鍏�)");
+            tabTitle.add("鍚堣(鍏�)");
+            tabTitle.add("澶囨敞");
+            tabParam.add(tabTitle);
+            int idx = 1;//tab搴忓彿
+            double totalPrice = 0D;
+            for (ContractSales contractSale : contractSales) {
+                ArrayList<String> list = new ArrayList<>();
+                list.add(String.valueOf(idx));
+                list.add(contractSale.getName());
+                list.add(String.valueOf(contractSale.getNum()));
+                list.add(contractSale.getUnit());
+                list.add(WordUtils.formatNumberForAccounting(contractSale.getUnitPrice()));
+                list.add(WordUtils.formatNumberForAccounting(contractSale.getTotalPrice()));
+                list.add(contractSale.getMemo());
+                tabParam.add(list);
+                totalPrice += contractSale.getTotalPrice();
+                idx++;//搴忓彿+1
+            }
+
+            //tab鏈�鍚庡悎璁℃爮
+            ArrayList<String> tabFooter = new ArrayList<>();
+            tabFooter.add("鍚堣锛堝ぇ鍐欓噾棰濓級锛�" + ChineseNumberUtils.numberToChinese(totalPrice));
+            tabFooter.add("");//鍚堝苟鍗曞厓鏍�
+            tabFooter.add("");//鍚堝苟鍗曞厓鏍�
+            tabFooter.add("");//鍚堝苟鍗曞厓鏍�
+            tabFooter.add("鍚堣锛�" + WordUtils.formatNumberForAccounting(totalPrice));
+            tabFooter.add("");//鍚堝苟鍗曞厓鏍�
+            tabFooter.add("");//鍚堝苟鍗曞厓鏍�
+            tabParam.add(tabFooter);
+            /////////////////////////鐢熸垚Tab琛ㄦ牸鏁版嵁/////////////////////////
+
+            String fileName = this.getClass().getClassLoader().getResource("contractTemplate/" + contractTemplate + ".docx").getPath();//鑾峰彇鏂囦欢璺緞
+            return WordUtils.generate(fileName, map, tabParam);
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    @RequestMapping(value = "/contract/upload/auth")
+    @ManagerAuth
+    public R upload(@RequestParam("id") Integer id,
+                         @RequestParam("file") MultipartFile[] files) throws IOException {
+        Contract contract = contractService.selectById(id);
+        if (contract == null) {
+            return R.error();
+        }
+
+        MultipartFile file = files[0];
+        SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd_HHmmss");
+        String path =  ClassUtils.getDefaultClassLoader().getResource("contractTemplate/upload").getPath();
+        //鏂囦欢鍚庣紑鍚�
+        String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
+        //涓婁紶鏂囦欢鍚�
+        String filename = format.format(new Date()) + suffix;
+        //鏈�缁堟枃浠惰矾寰�
+        String filepath = path + "/" + filename;
+        //OSS鏂囦欢瀛樺偍璺緞
+        String ossPath = "contract/" + filename;
+
+        //鏈嶅姟鍣ㄧ淇濆瓨鐨勬枃浠跺璞�
+        File serverFile = new File(filepath);
+        if(!serverFile.exists()) {
+            try {
+                //鍒涘缓鏂囦欢
+                serverFile.createNewFile();
+                //灏嗕笂浼犵殑鏂囦欢鍐欏叆鍒版湇鍔″櫒绔枃浠跺唴
+                file.transferTo(serverFile);
+
+                //涓婁紶鑷砄SS
+                ossService.uploadFile(ossPath, serverFile);
+                contract.setFilepath(ossPath);
+                contractService.updateById(contract);
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+        return R.ok();
+    }
+
+    @RequestMapping(value = "/contract/download/auth")
+    @ManagerAuth
+    public ResponseEntity<InputStreamResource> download(@RequestParam("id") Integer id) {
+        Contract contract = contractService.selectById(id);
+        if (contract == null) {
+            return null;
+        }
+        if (Cools.isEmpty(contract.getFilepath())) {
+            return null;
+        }
+
+        try {
+            return ossService.downloadFile(contract.getFilepath());//浠嶰SS涓笅杞芥枃浠�
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    @RequestMapping(value = "/contract/export/auth")
+    @ManagerAuth
+    public R export(@RequestBody JSONObject param){
+        EntityWrapper<Contract> wrapper = new EntityWrapper<>();
+        List<String> fields = JSONObject.parseArray(param.getJSONArray("fields").toJSONString(), String.class);
+        Map<String, Object> map = excludeTrash(param.getJSONObject("contract"));
+        convert(map, wrapper);
+        List<Contract> list = contractService.selectList(wrapper);
+        return R.ok(exportSupport(list, fields));
+    }
+
+    @RequestMapping(value = "/contractQuery/auth")
+    @ManagerAuth
+    public R query(String condition) {
+        EntityWrapper<Contract> wrapper = new EntityWrapper<>();
+        wrapper.like("id", condition);
+        Page<Contract> page = contractService.selectPage(new Page<>(0, 10), wrapper);
+        List<Map<String, Object>> result = new ArrayList<>();
+        for (Contract contract : page.getRecords()){
+            Map<String, Object> map = new HashMap<>();
+            map.put("id", contract.getId());
+            map.put("value", contract.getId());
+            result.add(map);
+        }
+        return R.ok(result);
+    }
+
+    @RequestMapping(value = "/contract/check/column/auth")
+    @ManagerAuth
+    public R query(@RequestBody JSONObject param) {
+        Wrapper<Contract> wrapper = new EntityWrapper<Contract>().eq(humpToLine(String.valueOf(param.get("key"))), param.get("val"));
+        if (null != contractService.selectOne(wrapper)){
+            return R.parse(BaseRes.REPEAT).add(getComment(Contract.class, String.valueOf(param.get("key"))));
+        }
+        return R.ok();
+    }
+
+    @RequestMapping("/contract/all/get/kv")
+    @ManagerAuth
+    public R getDataKV(@RequestParam(required = false) String condition) {
+        List<KeyValueVo> vos = new ArrayList<>();
+        Wrapper<Contract> wrapper = new EntityWrapper<Contract>().andNew().like("id", condition).orderBy("create_time", false);
+        contractService.selectPage(new Page<>(1, 30), wrapper).getRecords().forEach(item -> vos.add(new KeyValueVo(String.valueOf(item.getId()), item.getId())));
+        return R.ok().add(vos);
+    }
+
+}
diff --git a/src/main/java/com/zy/crm/manager/controller/ContractSalesController.java b/src/main/java/com/zy/crm/manager/controller/ContractSalesController.java
new file mode 100644
index 0000000..ee491db
--- /dev/null
+++ b/src/main/java/com/zy/crm/manager/controller/ContractSalesController.java
@@ -0,0 +1,135 @@
+package com.zy.crm.manager.controller;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.mapper.EntityWrapper;
+import com.baomidou.mybatisplus.mapper.Wrapper;
+import com.baomidou.mybatisplus.plugins.Page;
+import com.core.common.DateUtils;
+import com.zy.crm.manager.entity.ContractSales;
+import com.zy.crm.manager.service.ContractSalesService;
+import com.core.annotations.ManagerAuth;
+import com.core.common.BaseRes;
+import com.core.common.Cools;
+import com.core.common.R;
+import com.core.domain.KeyValueVo;
+import com.zy.crm.common.web.BaseController;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.*;
+
+@RestController
+public class ContractSalesController extends BaseController {
+
+    @Autowired
+    private ContractSalesService contractSalesService;
+
+    @RequestMapping(value = "/contractSales/{id}/auth")
+    @ManagerAuth
+    public R get(@PathVariable("id") String id) {
+        return R.ok(contractSalesService.selectById(String.valueOf(id)));
+    }
+
+    @RequestMapping(value = "/contractSales/list/auth")
+    @ManagerAuth
+    public R list(@RequestParam(defaultValue = "1")Integer curr,
+                  @RequestParam(defaultValue = "10")Integer limit,
+                  @RequestParam(required = false)String orderByField,
+                  @RequestParam(required = false)String orderByType,
+                  @RequestParam(required = false)String condition,
+                  @RequestParam Map<String, Object> param){
+        EntityWrapper<ContractSales> wrapper = new EntityWrapper<>();
+        excludeTrash(param);
+        convert(param, wrapper);
+        allLike(ContractSales.class, param.keySet(), wrapper, condition);
+        if (!Cools.isEmpty(orderByField)){wrapper.orderBy(humpToLine(orderByField), "asc".equals(orderByType));}
+        return R.ok(contractSalesService.selectPage(new Page<>(curr, limit), wrapper));
+    }
+
+    private <T> void convert(Map<String, Object> map, EntityWrapper<T> wrapper){
+        for (Map.Entry<String, Object> entry : map.entrySet()){
+            String val = String.valueOf(entry.getValue());
+            if (val.contains(RANGE_TIME_LINK)){
+                String[] dates = val.split(RANGE_TIME_LINK);
+                wrapper.ge(entry.getKey(), DateUtils.convert(dates[0]));
+                wrapper.le(entry.getKey(), DateUtils.convert(dates[1]));
+            } else {
+                wrapper.like(entry.getKey(), val);
+            }
+        }
+    }
+
+    @RequestMapping(value = "/contractSales/add/auth")
+    @ManagerAuth
+    public R add(ContractSales contractSales) {
+        contractSalesService.insert(contractSales);
+        return R.ok();
+    }
+
+	@RequestMapping(value = "/contractSales/update/auth")
+	@ManagerAuth
+    public R update(ContractSales contractSales){
+        if (Cools.isEmpty(contractSales) || null==contractSales.getId()){
+            return R.error();
+        }
+        contractSalesService.updateById(contractSales);
+        return R.ok();
+    }
+
+    @RequestMapping(value = "/contractSales/delete/auth")
+    @ManagerAuth
+    public R delete(@RequestParam(value="ids[]") Long[] ids){
+         for (Long id : ids){
+            contractSalesService.deleteById(id);
+        }
+        return R.ok();
+    }
+
+    @RequestMapping(value = "/contractSales/export/auth")
+    @ManagerAuth
+    public R export(@RequestBody JSONObject param){
+        EntityWrapper<ContractSales> wrapper = new EntityWrapper<>();
+        List<String> fields = JSONObject.parseArray(param.getJSONArray("fields").toJSONString(), String.class);
+        Map<String, Object> map = excludeTrash(param.getJSONObject("contractSales"));
+        convert(map, wrapper);
+        List<ContractSales> list = contractSalesService.selectList(wrapper);
+        return R.ok(exportSupport(list, fields));
+    }
+
+    @RequestMapping(value = "/contractSalesQuery/auth")
+    @ManagerAuth
+    public R query(String condition) {
+        EntityWrapper<ContractSales> wrapper = new EntityWrapper<>();
+        wrapper.like("id", condition);
+        Page<ContractSales> page = contractSalesService.selectPage(new Page<>(0, 10), wrapper);
+        List<Map<String, Object>> result = new ArrayList<>();
+        for (ContractSales contractSales : page.getRecords()){
+            Map<String, Object> map = new HashMap<>();
+            map.put("id", contractSales.getId());
+            map.put("value", contractSales.getId());
+            result.add(map);
+        }
+        return R.ok(result);
+    }
+
+    @RequestMapping(value = "/contractSales/check/column/auth")
+    @ManagerAuth
+    public R query(@RequestBody JSONObject param) {
+        Wrapper<ContractSales> wrapper = new EntityWrapper<ContractSales>().eq(humpToLine(String.valueOf(param.get("key"))), param.get("val"));
+        if (null != contractSalesService.selectOne(wrapper)){
+            return R.parse(BaseRes.REPEAT).add(getComment(ContractSales.class, String.valueOf(param.get("key"))));
+        }
+        return R.ok();
+    }
+
+    @RequestMapping("/contractSales/all/get/kv")
+    @ManagerAuth
+    public R getDataKV(@RequestParam(required = false) String condition) {
+        List<KeyValueVo> vos = new ArrayList<>();
+        Wrapper<ContractSales> wrapper = new EntityWrapper<ContractSales>().andNew().like("id", condition).orderBy("create_time", false);
+        contractSalesService.selectPage(new Page<>(1, 30), wrapper).getRecords().forEach(item -> vos.add(new KeyValueVo(String.valueOf(item.getId()), item.getId())));
+        return R.ok().add(vos);
+    }
+
+}
diff --git a/src/main/java/com/zy/crm/manager/controller/WordController.java b/src/main/java/com/zy/crm/manager/controller/WordController.java
new file mode 100644
index 0000000..132d751
--- /dev/null
+++ b/src/main/java/com/zy/crm/manager/controller/WordController.java
@@ -0,0 +1,155 @@
+package com.zy.crm.manager.controller;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import org.apache.poi.xwpf.usermodel.*;
+import org.apache.xmlbeans.XmlCursor;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.STMerge;
+import org.springframework.core.io.InputStreamResource;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@RestController
+public class WordController {
+
+    @GetMapping("/generateWord")
+    public ResponseEntity<InputStreamResource> generateWord() throws IOException {
+        // 璇诲彇 Word 妯℃澘鏂囦欢
+        String fileName = this.getClass().getClassLoader().getResource("word1.docx").getPath();//鑾峰彇鏂囦欢璺緞
+        File file = new File(fileName);
+        FileInputStream inputStream = new FileInputStream(file);
+        XWPFDocument document = new XWPFDocument(inputStream);
+
+        insertTab("${table}", document);
+
+        HashMap<String, Object> map = new HashMap<>();
+        map.put("${table}", "");
+        map.put("${name}", "寮犱笁");
+        processParagraphs(document.getParagraphs(), map, document);
+
+        // 灏嗘枃妗e啓鍏ヨ緭鍑烘祦
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        document.write(outputStream);
+        outputStream.close();
+
+        // 鍒涘缓鍝嶅簲瀹炰綋锛屽皢杈撳嚭娴佷綔涓烘枃浠跺唴瀹硅繑鍥�
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
+        headers.setContentDispositionFormData("attachment", "output.docx");
+        InputStreamResource resource = new InputStreamResource(new ByteArrayInputStream(outputStream.toByteArray()));
+        return ResponseEntity.ok()
+                .headers(headers)
+                .body(resource);
+    }
+
+    /**
+     * 澶勭悊娈佃惤涓枃鏈紝鏇挎崲鏂囨湰涓畾涔夌殑鍙橀噺锛�
+     * @param paragraphList 娈佃惤鍒楄〃
+     * @param param 闇�瑕佹浛鎹㈢殑鍙橀噺鍙婂彉閲忓��
+     * @param doc 闇�瑕佹浛鎹㈢殑DOC
+     */
+    public static void processParagraphs(List<XWPFParagraph> paragraphList, HashMap<String, Object> param, XWPFDocument doc) {
+        if (paragraphList != null && paragraphList.size() > 0) {
+            for (XWPFParagraph paragraph : paragraphList) {
+                List<XWPFRun> runs = paragraph.getRuns();
+                for (XWPFRun run : runs) {
+                    String text = run.getText(0);
+                    if (text != null) {
+                        boolean isSetText = false;
+                        for (Map.Entry<String, Object> entry : param.entrySet()) {
+                            String key = entry.getKey();
+                            if (text.indexOf(key) != -1) {
+                                isSetText = true;
+                                Object value = entry.getValue();
+                                if (value instanceof String) {// 鏂囨湰鏇挎崲
+                                    text = text.replace(key, value.toString());
+                                }
+                            }
+                        }
+                        if (isSetText) {
+                            run.setText(text, 0);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * 鍦ㄥ畾浣嶇殑浣嶇疆鎻掑叆琛ㄦ牸
+     */
+    public static void insertTab(String key, XWPFDocument doc2) {
+        List<XWPFParagraph> paragraphList = doc2.getParagraphs();
+        if (paragraphList != null && paragraphList.size() > 0) {
+            for (XWPFParagraph paragraph : paragraphList) {
+                List<XWPFRun> runs = paragraph.getRuns();
+                for (XWPFRun run : runs) {
+                    String text = run.getText(0);
+                    if (text != null) {
+                        if (text.indexOf(key) >= 0) {
+                            XmlCursor cursor = paragraph.getCTP().newCursor();
+                            XWPFTable tableOne = doc2.insertNewTbl(cursor);// ---杩欎釜鏄叧閿�
+                            String test = "[\n" +
+                                    "  [\"搴忓彿\",\"鍝佸悕\",\"鏁伴噺\",\"鍗曚綅\",\"鍗曚环(鍏�)\",\"鍚堣(鍏�)\",\"澶囨敞\"],\n" +
+                                    "  [\"1\",\"鑷姩鍖栫珛浣撲粨搴撹澶嘰",\"1\",\"濂梊",\"130000\",\"130000\",\"澶囨敞\"],\n" +
+                                    "  [\"鍚堣锛堝ぇ鍐欓噾棰濓級锛歕",\"\",\"\",\"\",\"鍚堣锛歕",\"\",\"\"]\n" +
+                                    "]";
+
+                            JSONArray row = JSON.parseArray(test);
+                            ArrayList<List<String>> list = new ArrayList<>();
+                            for (Object o : row) {
+                                ArrayList<String> arrayList = new ArrayList<>();
+                                JSONArray objects = JSON.parseArray(o.toString());
+                                for (Object object : objects) {
+                                    arrayList.add(object.toString());
+                                }
+                                list.add(arrayList);
+                            }
+
+                            int rows = list.size();
+                            int cols = list.get(0).size();
+                            for (int i = 0; i < rows; i++) {
+                                XWPFTableRow tableRow = null;
+                                if (i == 0) {
+                                    tableRow = tableOne.getRow(i);
+                                }else {
+                                    tableRow = tableOne.createRow();
+                                }
+
+                                for (int j = 0; j < cols; j++) {
+                                    if (i == 0 && j == 0) {
+                                        tableRow.getCell(j).setText(list.get(i).get(j));
+                                    }else {
+                                        XWPFTableCell cell = tableRow.getCell(j);
+                                        if (cell == null) {
+                                            tableRow.addNewTableCell().setText(list.get(i).get(j));
+                                        }else {
+                                            cell.setText(list.get(i).get(j));
+                                        }
+                                    }
+                                }
+                            }
+
+                            //鍚堝苟鏈�鍚庝竴琛屽崟鍏冩牸
+                            tableOne.getRow(rows - 1).getCell(0).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);
+                            tableOne.getRow(rows - 1).getCell(1).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);
+                            tableOne.getRow(rows - 1).getCell(2).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);
+                            tableOne.getRow(rows - 1).getCell(4).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);
+                            tableOne.getRow(rows - 1).getCell(5).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+}
diff --git a/src/main/java/com/zy/crm/manager/entity/Contract.java b/src/main/java/com/zy/crm/manager/entity/Contract.java
new file mode 100644
index 0000000..713659f
--- /dev/null
+++ b/src/main/java/com/zy/crm/manager/entity/Contract.java
@@ -0,0 +1,271 @@
+package com.zy.crm.manager.entity;
+
+import com.core.common.Cools;import com.baomidou.mybatisplus.annotations.TableId;
+import com.baomidou.mybatisplus.enums.IdType;
+import com.baomidou.mybatisplus.annotations.TableField;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import com.core.common.SpringUtils;
+import com.zy.crm.system.entity.User;
+import com.zy.crm.system.service.UserService;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import com.baomidou.mybatisplus.annotations.TableName;
+import java.io.Serializable;
+
+@Data
+@TableName("man_contract")
+public class Contract implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value= "")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 鐢叉柟
+     */
+    @ApiModelProperty(value= "鐢叉柟")
+    private String customer;
+
+    /**
+     * 鐢叉柟鍦板潃
+     */
+    @ApiModelProperty(value= "鐢叉柟鍦板潃")
+    private String address;
+
+    /**
+     * 鍏徃鍚嶇О
+     */
+    @ApiModelProperty(value= "鍏徃鍚嶇О")
+    private String company;
+
+    /**
+     * 鍏徃鍦板潃
+     */
+    @ApiModelProperty(value= "鍏徃鍦板潃")
+    @TableField("company_address")
+    private String companyAddress;
+
+    /**
+     * 鍏徃绋庡彿
+     */
+    @ApiModelProperty(value= "鍏徃绋庡彿")
+    @TableField("tax_num")
+    private String taxNum;
+
+    /**
+     * 寮�鎴烽摱琛�
+     */
+    @ApiModelProperty(value= "寮�鎴烽摱琛�")
+    private String bank;
+
+    /**
+     * 閾惰璐﹀彿
+     */
+    @ApiModelProperty(value= "閾惰璐﹀彿")
+    @TableField("bank_num")
+    private String bankNum;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    @ApiModelProperty(value= "鍒涘缓鏃堕棿")
+    @TableField("create_time")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    private Date createTime;
+
+    /**
+     * 鏇存柊鏃堕棿
+     */
+    @ApiModelProperty(value= "鏇存柊鏃堕棿")
+    @TableField("update_time")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    private Date updateTime;
+
+    /**
+     * 鍒涘缓浜哄憳
+     */
+    @ApiModelProperty(value= "鍒涘缓浜哄憳")
+    @TableField("create_by")
+    private Long createBy;
+
+    /**
+     * 鏇存柊浜哄憳
+     */
+    @ApiModelProperty(value= "鏇存柊浜哄憳")
+    @TableField("update_by")
+    private Long updateBy;
+
+    /**
+     * 涓婁紶鍚堝悓鍦板潃
+     */
+    @ApiModelProperty(value= "涓婁紶鍚堝悓鍦板潃")
+    private String filepath;
+
+    /**
+     * 鍩庡競
+     */
+    @ApiModelProperty(value= "鍩庡競")
+    private String city;
+
+    /**
+     * 鏀惰揣鍦板潃
+     */
+    @ApiModelProperty(value= "鏀惰揣鍦板潃")
+    @TableField("shipping_address")
+    private String shippingAddress;
+
+    /**
+     * 鏀惰揣浜�
+     */
+    @ApiModelProperty(value= "鏀惰揣浜�")
+    @TableField("shipping_name")
+    private String shippingName;
+
+    /**
+     * 鏀惰揣浜虹數璇�
+     */
+    @ApiModelProperty(value= "鏀惰揣浜虹數璇�")
+    @TableField("shipping_phone")
+    private String shippingPhone;
+
+    /**
+     * 鍚堝悓鎬婚噾棰�
+     */
+    @ApiModelProperty(value= "鍚堝悓鎬婚噾棰�")
+    private Double price;
+
+    /**
+     * 鐢靛瓙閭
+     */
+    @ApiModelProperty(value= "鐢靛瓙閭")
+    private String email;
+
+    /**
+     * 鍚堝悓鍚嶇О
+     */
+    @ApiModelProperty(value= "鍚堝悓鍚嶇О")
+    private String name;
+
+    /**
+     * 鍚堝悓鐘舵�亄1:姝e父,0:绂佹}
+     */
+    @ApiModelProperty(value= "鍚堝悓鐘舵�亄1:姝e父,0:绂佹}")
+    private Integer status;
+
+    /**
+     * 澶囨敞
+     */
+    @ApiModelProperty(value= "澶囨敞")
+    private String memo;
+
+    /**
+     * 娉曚汉鎴栨巿鏉冧唬琛�
+     */
+    @ApiModelProperty(value= "娉曚汉鎴栨巿鏉冧唬琛�")
+    private String boss;
+
+    public Contract() {}
+
+    public Contract(Long id, String customer, String address, String company, String companyAddress, String taxNum, String bank, String bankNum, Date createTime, Date updateTime, Long createBy, Long updateBy, String filepath, String city, String shippingAddress, String shippingName, String shippingPhone, Double price, String email, String name, Integer status, String memo, String boss) {
+        this.id = id;
+        this.customer = customer;
+        this.address = address;
+        this.company = company;
+        this.companyAddress = companyAddress;
+        this.taxNum = taxNum;
+        this.bank = bank;
+        this.bankNum = bankNum;
+        this.createTime = createTime;
+        this.updateTime = updateTime;
+        this.createBy = createBy;
+        this.updateBy = updateBy;
+        this.filepath = filepath;
+        this.city = city;
+        this.shippingAddress = shippingAddress;
+        this.shippingName = shippingName;
+        this.shippingPhone = shippingPhone;
+        this.price = price;
+        this.email = email;
+        this.name = name;
+        this.status = status;
+        this.memo = memo;
+        this.boss = boss;
+    }
+
+    //    Contract contract = new Contract(
+//            null,    // [闈炵┖]
+//            null,    // 鐢叉柟
+//            null,    // 鐢叉柟鍦板潃
+//            null,    // 鍏徃鍚嶇О
+//            null,    // 鍏徃鍦板潃
+//            null,    // 鍏徃绋庡彿
+//            null,    // 寮�鎴烽摱琛�
+//            null,    // 閾惰璐﹀彿
+//            null,    // 鍒涘缓鏃堕棿
+//            null,    // 鏇存柊鏃堕棿
+//            null,    // 鍒涘缓浜哄憳
+//            null,    // 鏇存柊浜哄憳
+//            null,    // 涓婁紶鍚堝悓鍦板潃
+//            null,    // 鍩庡競
+//            null,    // 鏀惰揣鍦板潃
+//            null,    // 鏀惰揣浜�
+//            null,    // 鏀惰揣浜虹數璇�
+//            null,    // 鍚堝悓鎬婚噾棰�
+//            null    // 鐢靛瓙閭
+//    );
+
+    public String getCreateTime$(){
+        if (Cools.isEmpty(this.createTime)){
+            return "";
+        }
+        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(this.createTime);
+    }
+
+    public String getUpdateTime$(){
+        if (Cools.isEmpty(this.updateTime)){
+            return "";
+        }
+        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(this.updateTime);
+    }
+
+    public String getCreateBy$() {
+        UserService userService = SpringUtils.getBean(UserService.class);
+        User user = userService.selectById(this.createBy);
+        if (!Cools.isEmpty(user)){
+            return String.valueOf(user.getNickname());
+        }
+        return null;
+    }
+
+    public String getUpdateBy$() {
+        UserService userService = SpringUtils.getBean(UserService.class);
+        User user = userService.selectById(this.updateBy);
+        if (!Cools.isEmpty(user)){
+            return String.valueOf(user.getNickname());
+        }
+        return null;
+    }
+
+    public String getStatus$() {
+        if (null == this.status){ return null; }
+        switch (this.status){
+            case 1:
+                return "姝e父";
+            case 0:
+                return "绂佺敤";
+            default:
+                return String.valueOf(this.status);
+        }
+    }
+
+
+
+}
diff --git a/src/main/java/com/zy/crm/manager/entity/ContractSales.java b/src/main/java/com/zy/crm/manager/entity/ContractSales.java
new file mode 100644
index 0000000..6557916
--- /dev/null
+++ b/src/main/java/com/zy/crm/manager/entity/ContractSales.java
@@ -0,0 +1,89 @@
+package com.zy.crm.manager.entity;
+
+import com.core.common.Cools;import com.baomidou.mybatisplus.annotations.TableId;
+import com.baomidou.mybatisplus.enums.IdType;
+import com.baomidou.mybatisplus.annotations.TableField;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import com.baomidou.mybatisplus.annotations.TableName;
+import java.io.Serializable;
+
+@Data
+@TableName("man_contract_sales")
+public class ContractSales implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value= "")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 鍝佸悕
+     */
+    @ApiModelProperty(value= "鍝佸悕")
+    private String name;
+
+    /**
+     * 鏁伴噺
+     */
+    @ApiModelProperty(value= "鏁伴噺")
+    private Double num;
+
+    /**
+     * 鍗曚綅
+     */
+    @ApiModelProperty(value= "鍗曚綅")
+    private String unit;
+
+    /**
+     * 鍗曚环
+     */
+    @ApiModelProperty(value= "鍗曚环")
+    @TableField("unit_price")
+    private Double unitPrice;
+
+    /**
+     * 鎬讳环
+     */
+    @ApiModelProperty(value= "鎬讳环")
+    @TableField("total_price")
+    private Double totalPrice;
+
+    /**
+     * 澶囨敞
+     */
+    @ApiModelProperty(value= "澶囨敞")
+    private String memo;
+
+    /**
+     * 鍚堝悓ID
+     */
+    @ApiModelProperty(value= "鍚堝悓ID")
+    private Long contractId;
+
+    public ContractSales() {}
+
+    public ContractSales(Long id, String name, Double num, String unit, Double unitPrice, Double totalPrice, String memo, Long contractId) {
+        this.id = id;
+        this.name = name;
+        this.num = num;
+        this.unit = unit;
+        this.unitPrice = unitPrice;
+        this.totalPrice = totalPrice;
+        this.memo = memo;
+        this.contractId = contractId;
+    }
+
+    //    ContractSales contractSales = new ContractSales(
+//            null,    // 鍝佸悕
+//            null,    // 鏁伴噺
+//            null,    // 鍗曚綅
+//            null,    // 鍗曚环
+//            null,    // 鎬讳环
+//            null    // 澶囨敞
+//    );
+
+
+}
diff --git a/src/main/java/com/zy/crm/manager/mapper/ContractMapper.java b/src/main/java/com/zy/crm/manager/mapper/ContractMapper.java
new file mode 100644
index 0000000..913e441
--- /dev/null
+++ b/src/main/java/com/zy/crm/manager/mapper/ContractMapper.java
@@ -0,0 +1,12 @@
+package com.zy.crm.manager.mapper;
+
+import com.zy.crm.manager.entity.Contract;
+import com.baomidou.mybatisplus.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.springframework.stereotype.Repository;
+
+@Mapper
+@Repository
+public interface ContractMapper extends BaseMapper<Contract> {
+
+}
diff --git a/src/main/java/com/zy/crm/manager/mapper/ContractSalesMapper.java b/src/main/java/com/zy/crm/manager/mapper/ContractSalesMapper.java
new file mode 100644
index 0000000..1fda689
--- /dev/null
+++ b/src/main/java/com/zy/crm/manager/mapper/ContractSalesMapper.java
@@ -0,0 +1,16 @@
+package com.zy.crm.manager.mapper;
+
+import com.zy.crm.manager.entity.ContractSales;
+import com.baomidou.mybatisplus.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Mapper
+@Repository
+public interface ContractSalesMapper extends BaseMapper<ContractSales> {
+
+    List<ContractSales> selectByContractId(Long contractId);
+
+}
diff --git a/src/main/java/com/zy/crm/manager/service/ContractSalesService.java b/src/main/java/com/zy/crm/manager/service/ContractSalesService.java
new file mode 100644
index 0000000..2b96404
--- /dev/null
+++ b/src/main/java/com/zy/crm/manager/service/ContractSalesService.java
@@ -0,0 +1,12 @@
+package com.zy.crm.manager.service;
+
+import com.zy.crm.manager.entity.ContractSales;
+import com.baomidou.mybatisplus.service.IService;
+
+import java.util.List;
+
+public interface ContractSalesService extends IService<ContractSales> {
+
+    List<ContractSales> selectByContractId(Long contractId);
+
+}
diff --git a/src/main/java/com/zy/crm/manager/service/ContractService.java b/src/main/java/com/zy/crm/manager/service/ContractService.java
new file mode 100644
index 0000000..46e4719
--- /dev/null
+++ b/src/main/java/com/zy/crm/manager/service/ContractService.java
@@ -0,0 +1,8 @@
+package com.zy.crm.manager.service;
+
+import com.zy.crm.manager.entity.Contract;
+import com.baomidou.mybatisplus.service.IService;
+
+public interface ContractService extends IService<Contract> {
+
+}
diff --git a/src/main/java/com/zy/crm/manager/service/impl/ContractSalesServiceImpl.java b/src/main/java/com/zy/crm/manager/service/impl/ContractSalesServiceImpl.java
new file mode 100644
index 0000000..6ca4e62
--- /dev/null
+++ b/src/main/java/com/zy/crm/manager/service/impl/ContractSalesServiceImpl.java
@@ -0,0 +1,18 @@
+package com.zy.crm.manager.service.impl;
+
+import com.zy.crm.manager.mapper.ContractSalesMapper;
+import com.zy.crm.manager.entity.ContractSales;
+import com.zy.crm.manager.service.ContractSalesService;
+import com.baomidou.mybatisplus.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service("contractSalesService")
+public class ContractSalesServiceImpl extends ServiceImpl<ContractSalesMapper, ContractSales> implements ContractSalesService {
+
+    @Override
+    public List<ContractSales> selectByContractId(Long contractId) {
+        return this.baseMapper.selectByContractId(contractId);
+    }
+}
diff --git a/src/main/java/com/zy/crm/manager/service/impl/ContractServiceImpl.java b/src/main/java/com/zy/crm/manager/service/impl/ContractServiceImpl.java
new file mode 100644
index 0000000..955f88a
--- /dev/null
+++ b/src/main/java/com/zy/crm/manager/service/impl/ContractServiceImpl.java
@@ -0,0 +1,12 @@
+package com.zy.crm.manager.service.impl;
+
+import com.zy.crm.manager.mapper.ContractMapper;
+import com.zy.crm.manager.entity.Contract;
+import com.zy.crm.manager.service.ContractService;
+import com.baomidou.mybatisplus.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+@Service("contractService")
+public class ContractServiceImpl extends ServiceImpl<ContractMapper, Contract> implements ContractService {
+
+}
diff --git a/src/main/java/com/zy/crm/manager/utils/ChineseNumberUtils.java b/src/main/java/com/zy/crm/manager/utils/ChineseNumberUtils.java
new file mode 100644
index 0000000..a75a430
--- /dev/null
+++ b/src/main/java/com/zy/crm/manager/utils/ChineseNumberUtils.java
@@ -0,0 +1,111 @@
+package com.zy.crm.manager.utils;
+
+//鏁板瓧涓枃澶у啓宸ュ叿绫�
+public class ChineseNumberUtils {
+
+    private static final String[] CN_NUMERIC = {"闆�", "澹�", "璐�", "鍙�", "鑲�", "浼�", "闄�", "鏌�", "鎹�", "鐜�"};
+
+    private static final String[] CN_CARRY = {"", "鎷�", "浣�", "浠�"};
+
+    private static final String[] CN_UNITS = {"", "涓�", "浜�", "鍏�"};
+
+    private static final String CN_FULL = "鏁�";
+
+    private static final String CN_NEGATIVE = "璐�";
+
+    public static String numberToChinese(double number) {
+        if (number == 0) {
+            return CN_NUMERIC[0];
+        }
+
+        long temp = (long) (number * 100);
+        int numFen = (int) (temp % 10);
+        temp = temp / 10;
+        int numJiao = (int) (temp % 10);
+        temp = temp / 10;
+        int[] parts = new int[20];
+        int numParts = 0;
+        for (int i = 0; temp != 0; i++) {
+            int partNum = (int) (temp % 10000);
+            parts[i] = partNum;
+            temp = temp / 10000;
+            numParts++;
+        }
+
+        boolean lastIsZero = true;
+        String chineseStr = "";
+        for (int i = 0; i < numParts; i++) {
+            if (parts[i] == 0) {
+                lastIsZero = true;
+                if (i == numParts - 1) {
+                    chineseStr = CN_UNITS[i] + chineseStr;
+                }
+                continue;
+            }
+            if (lastIsZero) {
+                chineseStr = CN_NUMERIC[0] + chineseStr;
+            }
+            String partChinese = partTranslate(parts[i]);
+            partChinese += CN_UNITS[i];
+            chineseStr = partChinese + chineseStr;
+            lastIsZero = false;
+        }
+
+        if (numFen == 0 && numJiao == 0) {
+            chineseStr += CN_FULL;
+        } else if (numFen == 0) {
+            chineseStr += CN_NUMERIC[numJiao] + "瑙�" + CN_FULL;
+        } else {
+            if (lastIsZero) {
+                chineseStr += CN_NUMERIC[0];
+            }
+            chineseStr += CN_NUMERIC[numJiao] + "瑙�" + CN_NUMERIC[numFen] + "鍒�";
+        }
+
+        return chineseStr;
+    }
+
+    private static String partTranslate(int partNum) {
+        if (partNum < 0 || partNum > 10000) {
+            return "";
+        }
+
+        String[] chNum = new String[4];
+        int unitPos = 0;
+        boolean zero = true;
+        while (partNum > 0) {
+            int num = partNum % 10;
+            if (num == 0) {
+                if (!zero) {
+                    zero = true;
+                    chNum[unitPos++] = CN_NUMERIC[num];
+                }
+            } else {
+                zero = false;
+                chNum[unitPos++] = CN_NUMERIC[num] + CN_CARRY[unitPos - 1];
+            }
+            partNum = partNum / 10;
+        }
+
+        StringBuilder strBuf = new StringBuilder();
+        boolean hasValue = false;
+        for (int i = 0; i < 4; i++) {
+            if (chNum[i] != null) {
+                if (i > 0 && !hasValue) {
+                    strBuf.insert(0, CN_NUMERIC[0]);
+                }
+                strBuf.insert(0, chNum[i]);
+                hasValue = true;
+            }
+        }
+
+        return strBuf.toString();
+    }
+
+    public static void main(String[] args) {
+        double number = 123456789.23;
+        String chineseNumber = numberToChinese(number);
+        System.out.println(chineseNumber);
+    }
+
+}
diff --git a/src/main/java/com/zy/crm/manager/utils/WordUtils.java b/src/main/java/com/zy/crm/manager/utils/WordUtils.java
new file mode 100644
index 0000000..c633862
--- /dev/null
+++ b/src/main/java/com/zy/crm/manager/utils/WordUtils.java
@@ -0,0 +1,175 @@
+package com.zy.crm.manager.utils;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import org.apache.poi.xwpf.usermodel.*;
+import org.apache.xmlbeans.XmlCursor;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.STMerge;
+import org.springframework.core.io.InputStreamResource;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+
+import java.io.*;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+//Word鎿嶄綔宸ュ叿绫�
+public class WordUtils {
+
+    //鐢熸垚word鍚堝悓
+    public static ResponseEntity<InputStreamResource> generate(String fileName, HashMap<String, Object> map, List<List<String>> tabParam) throws IOException {
+        // 璇诲彇 Word 妯℃澘鏂囦欢
+        File file = new File(fileName);
+        FileInputStream inputStream = new FileInputStream(file);
+        XWPFDocument document = new XWPFDocument(inputStream);
+
+        insertTab("{{table}}", document, tabParam);
+
+        map.put("{{table}}", "");
+        processParagraphs(map, document);
+
+        // 灏嗘枃妗e啓鍏ヨ緭鍑烘祦
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        document.write(outputStream);
+        outputStream.close();
+
+        // 鍒涘缓鍝嶅簲瀹炰綋锛屽皢杈撳嚭娴佷綔涓烘枃浠跺唴瀹硅繑鍥�
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
+        headers.setContentDispositionFormData("attachment", "output.docx");
+        InputStreamResource resource = new InputStreamResource(new ByteArrayInputStream(outputStream.toByteArray()));
+        return ResponseEntity.ok()
+                .headers(headers)
+                .body(resource);
+    }
+
+    /**
+     * 澶勭悊娈佃惤涓枃鏈紝鏇挎崲鏂囨湰涓畾涔夌殑鍙橀噺锛�
+     * @param param 闇�瑕佹浛鎹㈢殑鍙橀噺鍙婂彉閲忓��
+     * @param document 闇�瑕佹浛鎹㈢殑DOC
+     */
+    public static void processParagraphs(HashMap<String, Object> param, XWPFDocument document) {
+        // 閬嶅巻鎵�鏈夋钀�
+        for (XWPFParagraph paragraph : document.getParagraphs()) {
+            for (Map.Entry<String, Object> entry : param.entrySet()) {
+                String key = entry.getKey();
+                String value = entry.getValue().toString();
+                // 鏇挎崲娈佃惤鏂囨湰
+                replaceTextInParagraph(paragraph, key, value);
+            }
+        }
+
+        // 閬嶅巻鎵�鏈夎〃鏍�
+        for (XWPFTable table : document.getTables()) {
+            // 閬嶅巻琛ㄦ牸涓殑姣忎釜鍗曞厓鏍�
+            for (XWPFTableRow row : table.getRows()) {
+                for (XWPFTableCell cell : row.getTableCells()) {
+                    for (Map.Entry<String, Object> entry : param.entrySet()) {
+                        String key = entry.getKey();
+                        String value = entry.getValue().toString();
+                        // 鏇挎崲琛ㄦ牸鍗曞厓鏍肩殑鏂囨湰
+                        replaceTextInParagraph(cell.getParagraphs().get(0), key, value);
+                    }
+                }
+            }
+        }
+    }
+
+    private static void replaceTextInParagraph(XWPFParagraph paragraph, String searchString, String replacementString) {
+        for (XWPFRun run : paragraph.getRuns()) {
+            // 鑾峰彇娈佃惤涓殑鏂囨湰
+            String text = run.getText(0);
+            if (text != null && text.contains(searchString)) {
+                // 浣跨敤姝e垯琛ㄨ揪寮忚繘琛屾浛鎹�
+                Pattern pattern = Pattern.compile(Pattern.quote(searchString));
+                Matcher matcher = pattern.matcher(text);
+                if (matcher.find()) {
+                    String replacedText = matcher.replaceAll(replacementString);
+                    // 鏇挎崲鏂囨湰
+                    run.setText(replacedText, 0);
+                }
+            }
+        }
+    }
+
+    /**
+     * 鍦ㄥ畾浣嶇殑浣嶇疆鎻掑叆琛ㄦ牸
+     */
+    public static void insertTab(String key, XWPFDocument document, List<List<String>> param) {
+        List<XWPFParagraph> paragraphList = document.getParagraphs();
+        if (paragraphList != null && paragraphList.size() > 0) {
+            for (XWPFParagraph paragraph : paragraphList) {
+                List<XWPFRun> runs = paragraph.getRuns();
+                for (XWPFRun run : runs) {
+                    String text = run.getText(0);
+                    if (text != null) {
+                        if (text.indexOf(key) >= 0) {
+                            XmlCursor cursor = paragraph.getCTP().newCursor();
+                            XWPFTable tableOne = document.insertNewTbl(cursor);// ---杩欎釜鏄叧閿�
+//                            String test = "[\n" +
+//                                    "  [\"搴忓彿\",\"鍝佸悕\",\"鏁伴噺\",\"鍗曚綅\",\"鍗曚环(鍏�)\",\"鍚堣(鍏�)\",\"澶囨敞\"],\n" +
+//                                    "  [\"1\",\"鑷姩鍖栫珛浣撲粨搴撹澶嘰",\"1\",\"濂梊",\"130000\",\"130000\",\"澶囨敞\"],\n" +
+//                                    "  [\"鍚堣锛堝ぇ鍐欓噾棰濓級锛歕",\"\",\"\",\"\",\"鍚堣锛歕",\"\",\"\"]\n" +
+//                                    "]";
+//
+//                            JSONArray row = JSON.parseArray(test);
+//                            ArrayList<List<String>> list = new ArrayList<>();
+//                            for (Object o : row) {
+//                                ArrayList<String> arrayList = new ArrayList<>();
+//                                JSONArray objects = JSON.parseArray(o.toString());
+//                                for (Object object : objects) {
+//                                    arrayList.add(object.toString());
+//                                }
+//                                list.add(arrayList);
+//                            }
+
+                            int rows = param.size();
+                            int cols = param.get(0).size();
+                            for (int i = 0; i < rows; i++) {
+                                XWPFTableRow tableRow = null;
+                                if (i == 0) {
+                                    tableRow = tableOne.getRow(i);
+                                } else {
+                                    tableRow = tableOne.createRow();
+                                }
+
+                                for (int j = 0; j < cols; j++) {
+                                    if (i == 0 && j == 0) {
+                                        tableRow.getCell(j).setText(param.get(i).get(j));
+                                    } else {
+                                        XWPFTableCell cell = tableRow.getCell(j);
+                                        if (cell == null) {
+                                            tableRow.addNewTableCell().setText(param.get(i).get(j));
+                                        } else {
+                                            cell.setText(param.get(i).get(j));
+                                        }
+                                    }
+                                }
+                            }
+
+                            //鍚堝苟鏈�鍚庝竴琛屽崟鍏冩牸
+                            tableOne.getRow(rows - 1).getCell(0).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);
+                            tableOne.getRow(rows - 1).getCell(1).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);
+                            tableOne.getRow(rows - 1).getCell(2).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);
+                            tableOne.getRow(rows - 1).getCell(4).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);
+                            tableOne.getRow(rows - 1).getCell(5).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    public static String formatNumberForAccounting(double number) {
+        NumberFormat formatter = new DecimalFormat("#,###.00");
+        return formatter.format(number);
+    }
+
+}
diff --git a/src/main/resources/contractTemplate/jcxm_1.docx b/src/main/resources/contractTemplate/jcxm_1.docx
new file mode 100644
index 0000000..55c9b7f
--- /dev/null
+++ b/src/main/resources/contractTemplate/jcxm_1.docx
Binary files differ
diff --git a/src/main/resources/contractTemplate/upload/lock b/src/main/resources/contractTemplate/upload/lock
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/main/resources/contractTemplate/upload/lock
diff --git a/src/main/resources/contractTemplate/zjxm_1.docx b/src/main/resources/contractTemplate/zjxm_1.docx
new file mode 100644
index 0000000..3dc3eab
--- /dev/null
+++ b/src/main/resources/contractTemplate/zjxm_1.docx
Binary files differ
diff --git a/src/main/resources/mapper/ContractMapper.xml b/src/main/resources/mapper/ContractMapper.xml
new file mode 100644
index 0000000..0dee7cc
--- /dev/null
+++ b/src/main/resources/mapper/ContractMapper.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.zy.crm.manager.mapper.ContractMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.zy.crm.manager.entity.Contract">
+        <result column="id" property="id" />
+        <result column="customer" property="customer" />
+        <result column="address" property="address" />
+        <result column="company" property="company" />
+        <result column="company_address" property="companyAddress" />
+        <result column="tax_num" property="taxNum" />
+        <result column="bank" property="bank" />
+        <result column="bank_num" property="bankNum" />
+        <result column="create_time" property="createTime" />
+        <result column="update_time" property="updateTime" />
+        <result column="create_by" property="createBy" />
+        <result column="update_by" property="updateBy" />
+        <result column="filepath" property="filepath" />
+        <result column="city" property="city" />
+        <result column="shipping_address" property="shippingAddress" />
+        <result column="shipping_name" property="shippingName" />
+        <result column="shipping_phone" property="shippingPhone" />
+        <result column="price" property="price" />
+        <result column="email" property="email" />
+        <result column="name" property="name" />
+        <result column="status" property="status" />
+        <result column="memo" property="memo" />
+        <result column="boss" property="boss" />
+
+    </resultMap>
+
+</mapper>
diff --git a/src/main/resources/mapper/ContractSalesMapper.xml b/src/main/resources/mapper/ContractSalesMapper.xml
new file mode 100644
index 0000000..d284751
--- /dev/null
+++ b/src/main/resources/mapper/ContractSalesMapper.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.zy.crm.manager.mapper.ContractSalesMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.zy.crm.manager.entity.ContractSales">
+        <id column="id" property="id" />
+        <result column="name" property="name" />
+        <result column="num" property="num" />
+        <result column="unit" property="unit" />
+        <result column="unit_price" property="unitPrice" />
+        <result column="total_price" property="totalPrice" />
+        <result column="memo" property="memo" />
+        <result column="contract_id" property="contractId" />
+
+    </resultMap>
+
+    <select id="selectByContractId" resultMap="BaseResultMap">
+        select * from man_contract_sales
+        where contract_id = #{contractId}
+    </select>
+
+</mapper>
diff --git a/src/main/webapp/static/js/contract/contract.js b/src/main/webapp/static/js/contract/contract.js
new file mode 100644
index 0000000..c99f6e3
--- /dev/null
+++ b/src/main/webapp/static/js/contract/contract.js
@@ -0,0 +1,431 @@
+var pageCurr;
+layui.config({
+    base: baseUrl + "/static/layui/lay/modules/"
+}).use(['table','laydate', 'form', 'admin'], function(){
+    var table = layui.table;
+    var $ = layui.jquery;
+    var layer = layui.layer;
+    var layDate = layui.laydate;
+    var form = layui.form;
+    var admin = layui.admin;
+
+    // 鏁版嵁娓叉煋
+    tableIns = table.render({
+        elem: '#contract',
+        headers: {token: localStorage.getItem('token')},
+        url: baseUrl+'/contract/list/auth',
+        page: true,
+        limit: 15,
+        limits: [15, 30, 50, 100, 200, 500],
+        toolbar: '#toolbar',
+        cellMinWidth: 50,
+        height: 'full-120',
+        cols: [[
+            {type: 'checkbox'}
+            ,{field: 'id', align: 'center',title: '#ID'}
+            ,{field: 'name', align: 'center',title: '鍚堝悓鍚嶇О'}
+            ,{field: 'customer', align: 'center',title: '鐢叉柟'}
+            ,{field: 'company', align: 'center',title: '鍏徃鍚嶇О'}
+            ,{field: 'status$', align: 'center',title: '鐘舵��'}
+            ,{field: 'createBy$', align: 'center',title: '娣诲姞浜哄憳'}
+            ,{field: 'createTime$', align: 'center',title: '娣诲姞鏃堕棿'}
+            ,{field: 'updateBy$', align: 'center',title: '淇敼浜哄憳'}
+            ,{field: 'updateTime$', align: 'center',title: '淇敼鏃堕棿'}
+            ,{field: 'memo', align: 'center',title: '澶囨敞'}
+
+            ,{fixed: 'right', title:'鎿嶄綔', align: 'center', toolbar: '#operate', width:400}
+        ]],
+        request: {
+            pageName: 'curr',
+            pageSize: 'limit'
+        },
+        parseData: function (res) {
+            return {
+                'code': res.code,
+                'msg': res.msg,
+                'count': res.data.total,
+                'data': res.data.records
+            }
+        },
+        response: {
+            statusCode: 200
+        },
+        done: function(res, curr, count) {
+            if (res.code === 403) {
+                top.location.href = baseUrl+"/";
+            }
+            pageCurr=curr;
+            limit();
+        }
+    });
+
+    // 鐩戝惉鎺掑簭浜嬩欢
+    table.on('sort(contract)', function (obj) {
+        var searchData = {};
+        $.each($('#search-box [name]').serializeArray(), function() {
+            searchData[this.name] = this.value;
+        });
+        searchData['orderByField'] = obj.field;
+        searchData['orderByType'] = obj.type;
+        tableIns.reload({
+            where: searchData,
+            page: {curr: 1}
+        });
+    });
+
+    // 鐩戝惉澶村伐鍏锋爮浜嬩欢
+    table.on('toolbar(contract)', function (obj) {
+        var checkStatus = table.checkStatus(obj.config.id).data;
+        switch(obj.event) {
+            case 'addData':
+                showEditModel();
+                break;
+            case 'deleteData':
+               if (checkStatus.length === 0) {
+                   layer.msg('璇烽�夋嫨瑕佸垹闄ょ殑鏁版嵁', {icon: 2});
+                   return;
+               }
+               del(checkStatus.map(function (d) {
+                   return d.id;
+               }));
+               break;
+            case 'exportData':
+                admin.confirm('纭畾瀵煎嚭Excel鍚�', {shadeClose: true}, function(){
+                    var titles=[];
+                    var fields=[];
+                    obj.config.cols[0].map(function (col) {
+                        if (col.type === 'normal' && col.hide === false && col.toolbar == null) {
+                            titles.push(col.title);
+                            fields.push(col.field);
+                        }
+                    });
+                    var exportData = {};
+                    $.each($('#search-box [name]').serializeArray(), function() {
+                        exportData[this.name] = this.value;
+                    });
+                    var param = {
+                        'contract': exportData,
+                        'fields': fields
+                    };
+                    $.ajax({
+                        url: baseUrl+"/contract/export/auth",
+                        headers: {'token': localStorage.getItem('token')},
+                        data: JSON.stringify(param),
+                        dataType:'json',
+                        contentType:'application/json;charset=UTF-8',
+                        method: 'POST',
+                        success: function (res) {
+                            layer.closeAll();
+                            if (res.code === 200) {
+                                table.exportFile(titles,res.data,'xls');
+                            } else if (res.code === 403) {
+                                top.location.href = baseUrl+"/";
+                            } else {
+                                layer.msg(res.msg, {icon: 2})
+                            }
+                        }
+                    });
+                });
+                break;
+        }
+    });
+
+    // 鐩戝惉琛屽伐鍏蜂簨浠�
+    table.on('tool(contract)', function(obj){
+        var data = obj.data;
+        switch (obj.event) {
+            case 'edit':
+                showEditModel(data);
+                break;
+            case "del":
+                del([data.id]);
+                break;
+            case "generate":
+                //鐢熸垚鍚堝悓
+                generate(data)
+                break
+            case "sales":
+                //鍚堝悓鏄庣粏
+                sales(data);
+                break
+            case "upload":
+                //涓婁紶鍚堝悓
+                upload(data)
+                break
+            case "download":
+                //涓嬭浇鍚堝悓
+                download(data)
+                break
+        }
+    });
+
+    /* 寮圭獥 - 鏂板銆佷慨鏀� */
+    function showEditModel(mData) {
+        admin.open({
+            type: 1,
+            area: '800px',
+            title: (mData ? '淇敼' : '娣诲姞') + '鍚堝悓',
+            content: $('#editDialog').html(),
+            success: function (layero, dIndex) {
+                layDateRender(mData);
+                form.val('detail', mData);
+                form.on('submit(editSubmit)', function (data) {
+                    var loadIndex = layer.load(2);
+                    $.ajax({
+                        url: baseUrl+"/contract/"+(mData?'update':'add')+"/auth",
+                        headers: {'token': localStorage.getItem('token')},
+                        data: data.field,
+                        method: 'POST',
+                        success: function (res) {
+                            layer.close(loadIndex);
+                            if (res.code === 200){
+                                layer.close(dIndex);
+                                layer.msg(res.msg, {icon: 1});
+                                tableReload();
+                            } else if (res.code === 403){
+                                top.location.href = baseUrl+"/";
+                            }else {
+                                layer.msg(res.msg, {icon: 2});
+                            }
+                        }
+                    })
+                    return false;
+                });
+                $(layero).children('.layui-layer-content').css('overflow', 'visible');
+                layui.form.render('select');
+            }
+        });
+    }
+
+    /* 鐢熸垚鍚堝悓 */
+    function generate(mData) {
+        admin.open({
+            type: 1,
+            area: '600px',
+            title: '鐢熸垚鍚堝悓',
+            content: $('#generateDialog').html(),
+            success: function (layero, dIndex) {
+                layDateRender(mData);
+                form.val('detail', mData);
+                form.on('submit(generateSubmit)', function (data) {
+                    var loadIndex = layer.load(2);
+                    $.ajax({
+                        url: baseUrl + "/contract/generate/auth",
+                        headers: {'token': localStorage.getItem('token')},
+                        data: data.field,
+                        method: 'GET',
+                        xhrFields: {
+                            responseType: "blob" // 璁剧疆鍝嶅簲绫诲瀷涓轰簩杩涘埗鏁版嵁
+                        },
+                        success: function (res) {
+                            // 鍒涘缓涓�涓复鏃剁殑涓嬭浇閾炬帴
+                            const url = window.URL.createObjectURL(res);
+                            // 鍒涘缓涓�涓殣钘忕殑 <a> 鍏冪礌骞惰缃笅杞介摼鎺�
+                            const a = document.createElement("a");
+                            a.style.display = "none";
+                            a.href = url;
+                            a.download = data.field.name + ".docx"; // 鎸囧畾涓嬭浇鐨勬枃浠跺悕
+                            document.body.appendChild(a);
+
+                            // 瑙﹀彂鐐瑰嚮浜嬩欢浠ュ紑濮嬩笅杞�
+                            a.click();
+
+                            // 娓呯悊涓存椂璧勬簮
+                            setTimeout(function() {
+                                window.URL.revokeObjectURL(url);
+                                document.body.removeChild(a);
+                            }, 100);
+
+                            layer.close(loadIndex);
+                            layer.close(dIndex);
+                        }
+                    })
+                    return false;
+                });
+                $(layero).children('.layui-layer-content').css('overflow', 'visible');
+                layui.form.render('select');
+            }
+        });
+    }
+
+    /* 鍚堝悓鏄庣粏 */
+    function sales(mData) {
+        layer.open({
+            type: 2,
+            title: '鍚堝悓鏄庣粏',
+            maxmin: true,
+            area: [top.detailWidth,top.detailHeight],
+            shadeClose: false,
+            content: '../contractSales/contractSales.html?contractId=' + mData.id,
+            success: function(layero, index){
+            }
+        });
+    }
+
+    //涓婁紶鍚堝悓
+    function upload(data) {
+        if (data.filepath == '' || data.filepath == null) {
+            layer.confirm('鏄惁涓婁紶鍚堝悓?', function(){
+                $("#uploadQuote").click()
+            });
+        }else {
+            layer.confirm('宸蹭笂浼犲悎鍚岋紝鏄惁缁х画瑕嗙洊涓婁紶?', function(){
+                $("#uploadQuote").click()
+            });
+        }
+
+        $("#uploadQuote").on("change",(evt) => {
+            var files = evt.target.files;
+            if(files==null || files.length==0){
+                alert("No files wait for import");
+                return;
+            }
+
+            let name = files[0].name;
+            let suffixArr = name.split("."), suffix = suffixArr[suffixArr.length-1];
+            // if(suffix!="xlsx"){
+            //     alert("Currently only supports the import of xlsx files");
+            //     return;
+            // }
+
+            let formData = new FormData($("#uploadFile")[0]);
+            formData.append("id", data.id);
+            $.ajax({
+                url: baseUrl + "/contract/upload/auth",
+                headers: {'token': localStorage.getItem('token')},
+                data: formData,
+                method: 'POST',
+                cache: false,
+                processData: false,
+                contentType: false,
+                success: function (res) {
+                    if (res.code == 200) {
+                        layer.msg('涓婁紶鎴愬姛',{time:1000},() => {
+                            parent.location.reload()
+                        })
+                    }else{
+                        layer.msg(res.msg,{time:1000},() => {
+                            parent.location.reload()
+                        })
+                    }
+                }
+            })
+        })
+    }
+
+    //涓嬭浇鍚堝悓
+    function download(data) {
+        $.ajax({
+            url: baseUrl+"/contract/download/auth",
+            headers: {'token': localStorage.getItem('token')},
+            data: data,
+            method: 'GET',
+            xhrFields: {
+                responseType: "blob" // 璁剧疆鍝嶅簲绫诲瀷涓轰簩杩涘埗鏁版嵁
+            },
+            success: function (res) {
+                // 鍒涘缓涓�涓复鏃剁殑涓嬭浇閾炬帴
+                const url = window.URL.createObjectURL(res);
+                // 鍒涘缓涓�涓殣钘忕殑 <a> 鍏冪礌骞惰缃笅杞介摼鎺�
+                const a = document.createElement("a");
+                a.style.display = "none";
+                a.href = url;
+
+                let list = data.filepath.split(".")
+                let suffix = "." + list[list.length - 1]//鑾峰彇鍚庣紑鍚�
+                a.download = data.name + suffix; // 鎸囧畾涓嬭浇鐨勬枃浠跺悕
+                document.body.appendChild(a);
+
+                // 瑙﹀彂鐐瑰嚮浜嬩欢浠ュ紑濮嬩笅杞�
+                a.click();
+
+                // 娓呯悊涓存椂璧勬簮
+                setTimeout(function() {
+                    window.URL.revokeObjectURL(url);
+                    document.body.removeChild(a);
+                }, 100);
+            }
+        });
+    }
+
+    /* 鍒犻櫎 */
+    function del(ids) {
+        layer.confirm('纭畾瑕佸垹闄ら�変腑鏁版嵁鍚楋紵', {
+            skin: 'layui-layer-admin',
+            shade: .1
+        }, function (i) {
+            layer.close(i);
+            var loadIndex = layer.load(2);
+            $.ajax({
+                url: baseUrl+"/contract/delete/auth",
+                headers: {'token': localStorage.getItem('token')},
+                data: {ids: ids},
+                method: 'POST',
+                success: function (res) {
+                    layer.close(loadIndex);
+                    if (res.code === 200){
+                        layer.msg(res.msg, {icon: 1});
+                        tableReload();
+                    } else if (res.code === 403){
+                        top.location.href = baseUrl+"/";
+                    } else {
+                        layer.msg(res.msg, {icon: 2});
+                    }
+                }
+            })
+        });
+    }
+
+    // 鎼滅储
+    form.on('submit(search)', function (data) {
+        pageCurr = 1;
+        tableReload(false);
+    });
+
+    // 閲嶇疆
+    form.on('submit(reset)', function (data) {
+        pageCurr = 1;
+        clearFormVal($('#search-box'));
+        tableReload(false);
+    });
+
+    // 鏃堕棿閫夋嫨鍣�
+    function layDateRender(data) {
+        setTimeout(function () {
+            layDate.render({
+                elem: '.layui-laydate-range'
+                ,type: 'datetime'
+                ,range: true
+            });
+            layDate.render({
+                elem: '#createTime\\$',
+                type: 'datetime',
+                value: data!==undefined?data['createTime\\$']:null
+            });
+            layDate.render({
+                elem: '#updateTime\\$',
+                type: 'datetime',
+                value: data!==undefined?data['updateTime\\$']:null
+            });
+
+        }, 300);
+    }
+    layDateRender();
+
+});
+
+// 鍏抽棴鍔ㄤ綔
+$(document).on('click','#data-detail-close', function () {
+    parent.layer.closeAll();
+});
+
+function tableReload(child) {
+    var searchData = {};
+    $.each($('#search-box [name]').serializeArray(), function() {
+        searchData[this.name] = this.value;
+    });
+    tableIns.reload({
+        where: searchData,
+        page: {curr: pageCurr}
+     });
+}
diff --git a/src/main/webapp/static/js/contractSales/contractSales.js b/src/main/webapp/static/js/contractSales/contractSales.js
new file mode 100644
index 0000000..700e8e1
--- /dev/null
+++ b/src/main/webapp/static/js/contractSales/contractSales.js
@@ -0,0 +1,262 @@
+var pageCurr;
+var pageCount = 0;
+layui.config({
+    base: baseUrl + "/static/layui/lay/modules/"
+}).use(['table','laydate', 'form', 'admin', 'xmSelect'], function(){
+    var table = layui.table;
+    var $ = layui.jquery;
+    var layer = layui.layer;
+    var layDate = layui.laydate;
+    var form = layui.form;
+    var admin = layui.admin;
+    var xmSelect = layui.xmSelect;
+
+    var contractId = getQueryVariable("contractId")
+    if (contractId != false) {
+        $("#contract_id").val(contractId)
+    }
+
+    // 鏁版嵁娓叉煋
+    tableIns = table.render({
+        elem: '#contractSales',
+        headers: {token: localStorage.getItem('token')},
+        url: baseUrl+'/contractSales/list/auth',
+        page: true,
+        limit: 15,
+        limits: [15, 30, 50, 100, 200, 500],
+        toolbar: '#toolbar',
+        cellMinWidth: 50,
+        height: 'full-120',
+        where: {contract_id: $('#contract_id').val()},
+        cols: [[
+            {type: 'checkbox'}
+            // ,{field: 'id', align: 'center',title: ''}
+            ,{field: 'name', align: 'center',title: '鍝佸悕'}
+            ,{field: 'num', align: 'center',title: '鏁伴噺'}
+            ,{field: 'unit', align: 'center',title: '鍗曚綅'}
+            ,{field: 'unitPrice', align: 'center',title: '鍗曚环'}
+            ,{field: 'totalPrice', align: 'center',title: '鎬讳环'}
+            ,{field: 'memo', align: 'center',title: '澶囨敞'}
+
+            ,{fixed: 'right', title:'鎿嶄綔', align: 'center', toolbar: '#operate', width:120}
+        ]],
+        request: {
+            pageName: 'curr',
+            pageSize: 'limit'
+        },
+        parseData: function (res) {
+            return {
+                'code': res.code,
+                'msg': res.msg,
+                'count': res.data.total,
+                'data': res.data.records
+            }
+        },
+        response: {
+            statusCode: 200
+        },
+        done: function(res, curr, count) {
+            if (res.code === 403) {
+                top.location.href = baseUrl+"/";
+            }
+            pageCurr=curr;pageCount=count;
+            limit();
+        }
+    });
+
+    // 鐩戝惉鎺掑簭浜嬩欢
+    table.on('sort(contractSales)', function (obj) {
+        var searchData = {};
+        $.each($('#search-box [name]').serializeArray(), function() {
+            searchData[this.name] = this.value;
+        });
+        searchData['orderByField'] = obj.field;
+        searchData['orderByType'] = obj.type;
+        tableIns.reload({
+            where: searchData,
+            page: {curr: 1}
+        });
+    });
+
+    // 鐩戝惉澶村伐鍏锋爮浜嬩欢
+    table.on('toolbar(contractSales)', function (obj) {
+        var checkStatus = table.checkStatus(obj.config.id).data;
+        switch(obj.event) {
+            case 'addData':
+                showEditModel();
+                break;
+            case 'deleteData':
+               if (checkStatus.length === 0) {
+                   layer.msg('璇烽�夋嫨瑕佸垹闄ょ殑鏁版嵁', {icon: 2});
+                   return;
+               }
+               del(checkStatus.map(function (d) {
+                   return d.id;
+               }));
+               break;
+            case 'exportData':
+                admin.confirm('纭畾瀵煎嚭Excel鍚�', {shadeClose: true}, function(){
+                    var titles=[];
+                    var fields=[];
+                    obj.config.cols[0].map(function (col) {
+                        if (col.type === 'normal' && col.hide === false && col.toolbar == null) {
+                            titles.push(col.title);
+                            fields.push(col.field);
+                        }
+                    });
+                    var exportData = {};
+                    $.each($('#search-box [name]').serializeArray(), function() {
+                        exportData[this.name] = this.value;
+                    });
+                    var param = {
+                        'contractSales': exportData,
+                        'fields': fields
+                    };
+                    $.ajax({
+                        url: baseUrl+"/contractSales/export/auth",
+                        headers: {'token': localStorage.getItem('token')},
+                        data: JSON.stringify(param),
+                        dataType:'json',
+                        contentType:'application/json;charset=UTF-8',
+                        method: 'POST',
+                        success: function (res) {
+                            layer.closeAll();
+                            if (res.code === 200) {
+                                table.exportFile(titles,res.data,'xls');
+                            } else if (res.code === 403) {
+                                top.location.href = baseUrl+"/";
+                            } else {
+                                layer.msg(res.msg, {icon: 2})
+                            }
+                        }
+                    });
+                });
+                break;
+        }
+    });
+
+    // 鐩戝惉琛屽伐鍏蜂簨浠�
+    table.on('tool(contractSales)', function(obj){
+        var data = obj.data;
+        switch (obj.event) {
+            case 'edit':
+                showEditModel(data);
+                break;
+            case "del":
+                del([data.id]);
+                break;
+        }
+    });
+
+    /* 寮圭獥 - 鏂板銆佷慨鏀� */
+    function showEditModel(mData) {
+        admin.open({
+            type: 1,
+            area: '600px',
+            title: (mData ? '淇敼' : '娣诲姞') + '',
+            content: $('#editDialog').html(),
+            success: function (layero, dIndex) {
+                layDateRender(mData);
+                form.val('detail', mData);
+                form.on('submit(editSubmit)', function (data) {
+                    var loadIndex = layer.load(2);
+                    data.field.contractId = $("#contract_id").val()
+                    $.ajax({
+                        url: baseUrl+"/contractSales/"+(mData?'update':'add')+"/auth",
+                        headers: {'token': localStorage.getItem('token')},
+                        data: data.field,
+                        method: 'POST',
+                        success: function (res) {
+                            layer.close(loadIndex);
+                            if (res.code === 200){
+                                layer.close(dIndex);
+                                layer.msg(res.msg, {icon: 1});
+                                tableReload();
+                            } else if (res.code === 403){
+                                top.location.href = baseUrl+"/";
+                            }else {
+                                layer.msg(res.msg, {icon: 2});
+                            }
+                        }
+                    })
+                    return false;
+                });
+                $(layero).children('.layui-layer-content').css('overflow', 'visible');
+                layui.form.render('select');
+            }
+        });
+    }
+
+    /* 鍒犻櫎 */
+    function del(ids) {
+        layer.confirm('纭畾瑕佸垹闄ら�変腑鏁版嵁鍚楋紵', {
+            skin: 'layui-layer-admin',
+            shade: .1
+        }, function (i) {
+            layer.close(i);
+            var loadIndex = layer.load(2);
+            $.ajax({
+                url: baseUrl+"/contractSales/delete/auth",
+                headers: {'token': localStorage.getItem('token')},
+                data: {ids: ids},
+                method: 'POST',
+                success: function (res) {
+                    layer.close(loadIndex);
+                    if (res.code === 200){
+                        layer.msg(res.msg, {icon: 1});
+                        tableReload();
+                    } else if (res.code === 403){
+                        top.location.href = baseUrl+"/";
+                    } else {
+                        layer.msg(res.msg, {icon: 2});
+                    }
+                }
+            })
+        });
+    }
+
+    // 鎼滅储
+    form.on('submit(search)', function (data) {
+        pageCurr = 1;
+        tableReload();
+    });
+
+    // 閲嶇疆
+    form.on('submit(reset)', function (data) {
+        pageCurr = 1;
+        clearFormVal($('#search-box'));
+        tableReload();
+    });
+
+    // 鏃堕棿閫夋嫨鍣�
+    function layDateRender(data) {
+        setTimeout(function () {
+            layDate.render({
+                elem: '.layui-laydate-range'
+                ,type: 'datetime'
+                ,range: true
+            });
+
+        }, 300);
+    }
+    layDateRender();
+
+
+
+});
+
+// 鍏抽棴鍔ㄤ綔
+$(document).on('click','#data-detail-close', function () {
+    parent.layer.closeAll();
+});
+
+function tableReload() {
+    var searchData = {};
+    $.each($('#search-box [name]').serializeArray(), function() {
+        searchData[this.name] = this.value;
+    });
+    tableIns.reload({
+        where: searchData,
+        page: {curr: pageCurr}
+    });
+}
diff --git a/src/main/webapp/views/contract/contract.html b/src/main/webapp/views/contract/contract.html
new file mode 100644
index 0000000..041ffd4
--- /dev/null
+++ b/src/main/webapp/views/contract/contract.html
@@ -0,0 +1,236 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <title></title>
+    <meta name="renderer" content="webkit">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
+    <link rel="stylesheet" href="../../static/layui/css/layui.css" media="all">
+    <link rel="stylesheet" href="../../static/css/admin.css?v=318" media="all">
+    <link rel="stylesheet" href="../../static/css/cool.css" media="all">
+</head>
+<body>
+
+<div class="layui-fluid">
+    <div class="layui-card">
+        <div class="layui-card-body">
+            <div class="layui-form toolbar" id="search-box">
+                <div class="layui-form-item">
+                    <div class="layui-inline">
+                        <div class="layui-input-inline">
+                            <input class="layui-input" type="text" name="id" placeholder="缂栧彿" autocomplete="off">
+                        </div>
+                    </div>
+                     <div class="layui-inline" style="width: 300px">
+                        <div class="layui-input-inline">
+                            <input class="layui-input layui-laydate-range" name="create_time" type="text" placeholder="璧峰鏃堕棿 - 缁堟鏃堕棿" autocomplete="off" style="width: 300px">
+                        </div>
+                    </div>
+                    <div class="layui-inline">
+                        <div class="layui-input-inline">
+                            <input class="layui-input" type="text" name="condition" placeholder="璇疯緭鍏�" autocomplete="off">
+                        </div>
+                    </div>
+                    <div class="layui-inline">&emsp;
+                        <button class="layui-btn icon-btn" lay-filter="search" lay-submit>
+                            <i class="layui-icon">&#xe615;</i>鎼滅储
+                        </button>
+                        <button class="layui-btn icon-btn" lay-filter="reset" lay-submit>
+                            <i class="layui-icon">&#xe666;</i>閲嶇疆
+                        </button>
+                    </div>
+                </div>
+            </div>
+            <table class="layui-hide" id="contract" lay-filter="contract"></table>
+        </div>
+    </div>
+</div>
+
+<form id="uploadFile" enctype="multipart/form-data" style="display: none;" >
+    <input type="file" name="file" id="uploadQuote">
+    <input type="button" onclick="upload()" value="涓婁紶"/>
+</form>
+
+<script type="text/html" id="toolbar">
+    <div class="layui-btn-container">
+        <button class="layui-btn layui-btn-sm" id="btn-add" lay-event="addData">鏂板</button>
+        <button class="layui-btn layui-btn-sm layui-btn-danger" id="btn-delete" lay-event="deleteData">鍒犻櫎</button>
+        <button class="layui-btn layui-btn-primary layui-btn-sm" id="btn-export" lay-event="exportData" style="float: right">瀵煎嚭</button>
+    </div>
+</script>
+
+<script type="text/html" id="operate">
+    <a class="layui-btn layui-btn-primary layui-btn-xs btn-edit" lay-event="edit">淇敼</a>
+    <a class="layui-btn layui-btn-primary layui-btn-xs btn-edit" lay-event="sales">鍚堝悓鏄庣粏</a>
+    <a class="layui-btn layui-btn-xs btn-edit" lay-event="generate">鐢熸垚鍚堝悓</a>
+    <a class="layui-btn layui-btn-xs btn-edit" lay-event="upload">涓婁紶鍚堝悓</a>
+    <a class="layui-btn layui-btn-xs btn-edit" lay-event="download">涓嬭浇</a>
+    <a class="layui-btn layui-btn-danger layui-btn-xs btn-edit" lay-event="del">鍒犻櫎</a>
+</script>
+
+<script type="text/javascript" src="../../static/js/jquery/jquery-3.3.1.min.js"></script>
+<script type="text/javascript" src="../../static/layui/layui.js" charset="utf-8"></script>
+<script type="text/javascript" src="../../static/js/common.js" charset="utf-8"></script>
+<script type="text/javascript" src="../../static/js/cool.js" charset="utf-8"></script>
+<script type="text/javascript" src="../../static/js/contract/contract.js" charset="utf-8"></script>
+</body>
+<!-- 琛ㄥ崟寮圭獥 -->
+<script type="text/html" id="editDialog">
+    <div id="detail" lay-filter="detail" class="layui-form admin-form model-form">
+        <input name="id" type="hidden">
+        <div class="layui-row">
+            <div class="layui-col-md6">
+                <div class="layui-form-item">
+                    <label class="layui-form-label layui-form-required">鍚堝悓鍚嶇О: </label>
+                    <div class="layui-input-block">
+                        <input class="layui-input" name="name" placeholder="璇疯緭鍏ュ悎鍚屽悕绉�" lay-verify="required">
+                    </div>
+                </div>
+                <div class="layui-form-item">
+                    <label class="layui-form-label layui-form-required">鐢叉柟: </label>
+                    <div class="layui-input-block">
+                        <input class="layui-input" name="customer" placeholder="璇疯緭鍏ョ敳鏂�" lay-verify="required">
+                    </div>
+                </div>
+                <div class="layui-form-item">
+                    <label class="layui-form-label layui-form-required">娉曚汉鎴栨巿鏉冧唬琛�: </label>
+                    <div class="layui-input-block">
+                        <input class="layui-input" name="boss" placeholder="璇疯緭鍏ユ硶浜烘垨鎺堟潈浠h〃" lay-verify="required">
+                    </div>
+                </div>
+                <div class="layui-form-item">
+                    <label class="layui-form-label layui-form-required">鐢叉柟鍦板潃: </label>
+                    <div class="layui-input-block">
+                        <input class="layui-input" name="address" placeholder="璇疯緭鍏ョ敳鏂瑰湴鍧�" lay-verify="required">
+                    </div>
+                </div>
+                <div class="layui-form-item">
+                    <label class="layui-form-label layui-form-required">鍏徃鍚嶇О: </label>
+                    <div class="layui-input-block">
+                        <input class="layui-input" name="company" placeholder="璇疯緭鍏ュ叕鍙稿悕绉�" lay-verify="required">
+                    </div>
+                </div>
+                <div class="layui-form-item">
+                    <label class="layui-form-label layui-form-required">鍏徃鍦板潃: </label>
+                    <div class="layui-input-block">
+                        <input class="layui-input" name="companyAddress" placeholder="璇疯緭鍏ュ叕鍙稿湴鍧�" lay-verify="required">
+                    </div>
+                </div>
+                <div class="layui-form-item">
+                    <label class="layui-form-label layui-form-required">鍏徃绋庡彿: </label>
+                    <div class="layui-input-block">
+                        <input class="layui-input" name="taxNum" placeholder="璇疯緭鍏ュ叕鍙哥◣鍙�" lay-verify="required">
+                    </div>
+                </div>
+                <div class="layui-form-item">
+                    <label class="layui-form-label layui-form-required">鏀惰揣浜�: </label>
+                    <div class="layui-input-block">
+                        <input class="layui-input" name="shippingName" placeholder="璇疯緭鍏ユ敹璐т汉" lay-verify="required">
+                    </div>
+                </div>
+                <div class="layui-form-item">
+                    <label class="layui-form-label layui-form-required">鏀惰揣浜虹數璇�: </label>
+                    <div class="layui-input-block">
+                        <input class="layui-input" name="shippingPhone" placeholder="璇疯緭鍏ユ敹璐т汉鐢佃瘽" lay-verify="required">
+                    </div>
+                </div>
+
+             </div>
+
+            <div class="layui-col-md6">
+                <div class="layui-form-item">
+                    <label class="layui-form-label layui-form-required">寮�鎴烽摱琛�: </label>
+                    <div class="layui-input-block">
+                        <input class="layui-input" name="bank" placeholder="璇疯緭鍏ュ紑鎴烽摱琛�" lay-verify="required">
+                    </div>
+                </div>
+                <div class="layui-form-item">
+                    <label class="layui-form-label layui-form-required">閾惰璐﹀彿: </label>
+                    <div class="layui-input-block">
+                        <input class="layui-input" name="bankNum" placeholder="璇疯緭鍏ラ摱琛岃处鍙�" lay-verify="required">
+                    </div>
+                </div>
+                <div class="layui-form-item">
+                    <label class="layui-form-label layui-form-required">鏀惰揣鍦板潃:</label>
+                    <div class="layui-input-block">
+                        <input class="layui-input" name="shippingAddress" placeholder="璇疯緭鍏ユ敹璐у湴鍧�" lay-verify="required">
+                    </div>
+                </div>
+                <div class="layui-form-item">
+                    <label class="layui-form-label layui-form-required">鍚堝悓鎬婚噾棰�: </label>
+                    <div class="layui-input-block">
+                        <input class="layui-input" name="price" placeholder="璇疯緭鍏ュ悎鍚屾�婚噾棰�" lay-verify="required">
+                    </div>
+                </div>
+                <div class="layui-form-item">
+                    <label class="layui-form-label">鐢靛瓙閭: </label>
+                    <div class="layui-input-block">
+                        <input class="layui-input" name="email" placeholder="璇疯緭鍏ョ數瀛愰偖绠�">
+                    </div>
+                </div>
+                <div class="layui-form-item">
+                    <label class="layui-form-label">鍩庡競: </label>
+                    <div class="layui-input-block">
+                        <input class="layui-input" name="city" placeholder="璇疯緭鍏ュ煄甯�">
+                    </div>
+                </div>
+                <div class="layui-form-item">
+                    <label class="layui-form-label layui-form-required">鍚堝悓鐘舵��: </label>
+                    <div class="layui-input-block">
+                        <select name="status" lay-vertype="tips" lay-verify="required">
+                            <option value="">璇烽�夋嫨鐘舵��</option>
+                            <option value="1">姝e父</option>
+                            <option value="0">绂佹</option>
+                        </select>
+                    </div>
+                </div>
+                <div class="layui-form-item">
+                    <label class="layui-form-label">澶囨敞: </label>
+                    <div class="layui-input-block">
+                        <input class="layui-input" name="memo" placeholder="璇疯緭鍏ュ娉�">
+                    </div>
+                </div>
+
+            </div>
+
+        </div>
+        <hr class="layui-bg-gray">
+        <div class="layui-form-item text-right">
+            <button class="layui-btn" lay-filter="editSubmit" lay-submit="">淇濆瓨</button>
+            <button class="layui-btn layui-btn-primary" type="button" ew-event="closeDialog">鍙栨秷</button>
+        </div>
+    </div>
+</script>
+
+<!-- 琛ㄥ崟寮圭獥 -->
+<script type="text/html" id="generateDialog">
+    <div id="detail1" lay-filter="detail" class="layui-form admin-form model-form">
+        <input name="id" type="hidden">
+        <div class="layui-row">
+            <div class="layui-col-md12">
+                <div class="layui-form-item">
+                    <label class="layui-form-label layui-form-required">鍚堝悓鍚嶇О: </label>
+                    <div class="layui-input-block">
+                        <input class="layui-input" name="name" placeholder="璇疯緭鍏ュ悎鍚屽悕绉�" disabled lay-verify="required">
+                    </div>
+                </div>
+                <div class="layui-form-item">
+                    <label class="layui-form-label layui-form-required">鍚堝悓妯℃澘: </label>
+                    <div class="layui-input-block">
+                        <input type="radio" name="contractTemplate" value="jcxm_1" title="闆嗘垚椤圭洰閿�鍞悎鍚屾ā鏉�" checked>
+                        <input type="radio" name="contractTemplate" value="zjxm_1" title="杞藉叿閿�鍞悎鍚屾ā鏉�">
+                    </div>
+                </div>
+            </div>
+
+        </div>
+        <hr class="layui-bg-gray">
+        <div class="layui-form-item text-right">
+            <button class="layui-btn" lay-filter="generateSubmit" lay-submit="">鐢熸垚</button>
+            <button class="layui-btn layui-btn-primary" type="button" ew-event="closeDialog">鍙栨秷</button>
+        </div>
+    </div>
+</script>
+</html>
+
diff --git a/src/main/webapp/views/contractSales/contractSales.html b/src/main/webapp/views/contractSales/contractSales.html
new file mode 100644
index 0000000..4116f43
--- /dev/null
+++ b/src/main/webapp/views/contractSales/contractSales.html
@@ -0,0 +1,127 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <title></title>
+    <meta name="renderer" content="webkit">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
+    <link rel="stylesheet" href="../../static/layui/css/layui.css" media="all">
+    <link rel="stylesheet" href="../../static/css/admin.css?v=318" media="all">
+    <link rel="stylesheet" href="../../static/css/cool.css" media="all">
+</head>
+<body>
+
+<div class="layui-fluid">
+    <div class="layui-card">
+        <div class="layui-card-body">
+            <div class="layui-form toolbar" id="search-box">
+                <div class="layui-form-item">
+                    <div class="layui-inline">
+                        <div class="layui-input-inline">
+                            <input class="layui-input" type="text" name="id" placeholder="缂栧彿" autocomplete="off">
+                        </div>
+                    </div>
+                    <div class="layui-inline">
+                        <div class="layui-input-inline">
+                            <input class="layui-input" type="text" name="contract_id" id="contract_id" placeholder="鍚堝悓ID" autocomplete="off">
+                        </div>
+                    </div>
+                     <div class="layui-inline" style="width: 300px">
+                        <div class="layui-input-inline">
+                            <input class="layui-input layui-laydate-range" name="create_time" type="text" placeholder="璧峰鏃堕棿 - 缁堟鏃堕棿" autocomplete="off" style="width: 300px">
+                        </div>
+                    </div>
+                    <div class="layui-inline">
+                        <div class="layui-input-inline">
+                            <input class="layui-input" type="text" name="condition" placeholder="璇疯緭鍏�" autocomplete="off">
+                        </div>
+                    </div>
+                    <div class="layui-inline">&emsp;
+                        <button class="layui-btn icon-btn" lay-filter="search" lay-submit>
+                            <i class="layui-icon">&#xe615;</i>鎼滅储
+                        </button>
+                        <button class="layui-btn icon-btn" lay-filter="reset" lay-submit>
+                            <i class="layui-icon">&#xe666;</i>閲嶇疆
+                        </button>
+                    </div>
+                </div>
+            </div>
+            <table class="layui-hide" id="contractSales" lay-filter="contractSales"></table>
+        </div>
+    </div>
+</div>
+
+<script type="text/html" id="toolbar">
+    <div class="layui-btn-container">
+        <button class="layui-btn layui-btn-sm" id="btn-add" lay-event="addData">鏂板</button>
+        <button class="layui-btn layui-btn-sm layui-btn-danger" id="btn-delete" lay-event="deleteData">鍒犻櫎</button>
+        <button class="layui-btn layui-btn-primary layui-btn-sm" id="btn-export" lay-event="exportData" style="float: right">瀵煎嚭</button>
+    </div>
+</script>
+
+<script type="text/html" id="operate">
+    <a class="layui-btn layui-btn-primary layui-btn-xs btn-edit" lay-event="edit">淇敼</a>
+    <a class="layui-btn layui-btn-danger layui-btn-xs btn-edit" lay-event="del">鍒犻櫎</a>
+</script>
+
+<script type="text/javascript" src="../../static/js/jquery/jquery-3.3.1.min.js"></script>
+<script type="text/javascript" src="../../static/layui/layui.js" charset="utf-8"></script>
+<script type="text/javascript" src="../../static/js/common.js" charset="utf-8"></script>
+<script type="text/javascript" src="../../static/js/cool.js" charset="utf-8"></script>
+<script type="text/javascript" src="../../static/js/contractSales/contractSales.js" charset="utf-8"></script>
+</body>
+<!-- 琛ㄥ崟寮圭獥 -->
+<script type="text/html" id="editDialog">
+    <div id="detail" lay-filter="detail" class="layui-form admin-form model-form">
+        <input name="id" type="hidden">
+        <div class="layui-row">
+            <div class="layui-col-md12">
+                <div class="layui-form-item">
+                    <label class="layui-form-label">鍝佸悕: </label>
+                    <div class="layui-input-block">
+                        <input class="layui-input" name="name" placeholder="璇疯緭鍏ュ搧鍚�">
+                    </div>
+                </div>
+                <div class="layui-form-item">
+                    <label class="layui-form-label">鏁伴噺: </label>
+                    <div class="layui-input-block">
+                        <input class="layui-input" name="num" placeholder="璇疯緭鍏ユ暟閲�">
+                    </div>
+                </div>
+                <div class="layui-form-item">
+                    <label class="layui-form-label">鍗曚綅: </label>
+                    <div class="layui-input-block">
+                        <input class="layui-input" name="unit" placeholder="璇疯緭鍏ュ崟浣�">
+                    </div>
+                </div>
+                <div class="layui-form-item">
+                    <label class="layui-form-label">鍗曚环: </label>
+                    <div class="layui-input-block">
+                        <input class="layui-input" name="unitPrice" placeholder="璇疯緭鍏ュ崟浠�">
+                    </div>
+                </div>
+                <div class="layui-form-item">
+                    <label class="layui-form-label">鎬讳环: </label>
+                    <div class="layui-input-block">
+                        <input class="layui-input" name="totalPrice" placeholder="璇疯緭鍏ユ�讳环">
+                    </div>
+                </div>
+                <div class="layui-form-item">
+                    <label class="layui-form-label">澶囨敞: </label>
+                    <div class="layui-input-block">
+                        <input class="layui-input" name="memo" placeholder="璇疯緭鍏ュ娉�">
+                    </div>
+                </div>
+
+             </div>
+        </div>
+        <hr class="layui-bg-gray">
+        <div class="layui-form-item text-right">
+            <button class="layui-btn" lay-filter="editSubmit" lay-submit="">淇濆瓨</button>
+            <button class="layui-btn layui-btn-primary" type="button" ew-event="closeDialog">鍙栨秷</button>
+        </div>
+    </div>
+</script>
+</html>
+

--
Gitblit v1.9.1