diff --git a/acs/nladmin-system/nlsso-server/src/main/java/org/nl/bx06_demo.java b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/bx06_demo.java
deleted file mode 100644
index bcae033..0000000
--- a/acs/nladmin-system/nlsso-server/src/main/java/org/nl/bx06_demo.java
+++ /dev/null
@@ -1,472 +0,0 @@
-package org.nl; /**
- * Created by admin on 2019/8/21.
- */
-
-import onbon.bx06.Bx6GEnv;
-import onbon.bx06.Bx6GScreen;
-import onbon.bx06.Bx6GScreenClient;
-import onbon.bx06.Bx6GScreenRS;
-import onbon.bx06.area.*;
-import onbon.bx06.area.page.ImageFileBxPage;
-import onbon.bx06.area.page.TextBxPage;
-import onbon.bx06.area.page.TextFileBxPage;
-import onbon.bx06.cmd.dyn.DynamicBxAreaRule;
-import onbon.bx06.file.ProgramBxFile;
-import onbon.bx06.message.common.ErrorType;
-import onbon.bx06.message.led.ReturnControllerStatus;
-import onbon.bx06.series.Bx6E;
-import onbon.bx06.utils.DisplayStyleFactory.DisplayStyle;
-import onbon.bx06.utils.DisplayStyleFactory;
-import onbon.bx06.utils.TextBinary;
-
-import java.awt.*;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * @program: bx06_demo
- * @description:
- * @author: Mr.Feng
- * @create: 2019-08-21 14:52
- **/
-public class bx06_demo {
-    private static String ip = "192.168.10.56";
-    private static int port = 5005;
-    public static void main(String[] args)throws Exception
-    {
-        // 初始化API,此操作只在程序启动时候执行一次即可,多次执行会出现内存错误
-        Bx6GEnv.initial(30000);
-        SendDynamicProgram();
-    }
-
-
-    // 动态区和节目一起播放
-    public static void SendDynamicProgram()throws Exception
-    {
-        DisplayStyle[] styles = DisplayStyleFactory.getStyles().toArray(new DisplayStyle[0]);
-
-        Bx6GScreenClient screen = new Bx6GScreenClient( "MyScreen",new Bx6E() );
-
-        screen.connect( ip,port );
-
-        ProgramBxFile pf = new ProgramBxFile( 0,screen.getProfile() );
-
-        TextCaptionBxArea area = new TextCaptionBxArea( 0,0,160,32,screen.getProfile() );
-
-        TextBxPage page = new TextBxPage( "入库模式" );
-
-        page.setFont(new Font( "宋体",Font.PLAIN,24 ));
-        area.addPage( page );
-
-        pf.addArea( area );
-
-        screen.writeProgram( pf );
-
-        DynamicBxAreaRule rule = new DynamicBxAreaRule();
-        rule.setId(0);
-        rule.setRunMode( (byte)0 );
-        // 新增动态区关联异步节目
-        // 一旦关联了某个异步节目,则该节目和动态区一起播放
-        // 设置动态区和节目关联
-        // 设定是否关联全部节目
-        // true: 所有异步节目播放是都允许播放该动态区
-        // false:由规则来决定
-        rule.setRelativeAllPrograms( false );
-        rule.addRelativeProgram( 0 );
-
-        DynamicBxArea dArea = new DynamicBxArea( 0,32,192,64,screen.getProfile() );
-
-        TextBxPage dPage = new TextBxPage( "TOOO1入库至L01-01-01,TOOO1入库至L01-01-01" );
-        dPage.setDisplayStyle( styles[4] );
-        dPage.setFont( new Font( "宋体",Font.PLAIN,28 ) );
-
-        dArea.addPage( dPage );
-
-        screen.writeDynamic( rule,dArea );
-
-        List<String> pfs = screen.readProgramList();
-        for(String program : pfs)
-        {
-            System.out.println( program );
-        }
-
-        screen.disconnect();
-    }
-
-    /*// 将一个节目发送到控制器
-    public static void SendProgram()throws Exception
-    {
-        // 关于显示特技
-        // 0:随机显示
-        // 1:静止显示
-        // 2:快速打出
-        // 3:向左移动
-        // 4:向左连移
-        // 5:向上移动
-        // 6:向上连移
-        // 7:闪烁
-        // 8:飘雪
-        // 9:冒泡
-        // 10:中间移出
-        // 11:左右移入
-        // 12:左右交叉移入
-        // 13:上下交叉移入
-        // 14:花卷闭合
-        // 15:花卷打开
-        // 16:向左拉伸
-        // 17:向右拉伸
-        // 18:向上拉伸
-        // 19:向下拉伸
-        // 20:向左镭射
-        // 21:向右镭射
-        // 22:向上镭射
-        // 23:向下镭射
-        // 24:左右交叉拉幕
-        // 25:上下交叉拉幕
-        // 26:分散左拉
-        // 27:水平百叶
-        // 28:垂直百叶
-        // 29:向左拉幕
-        // 30:向右拉幕
-        // 31:向上拉幕
-        // 32:向下拉幕
-        // 33:左右闭合
-        // 34:左右对开
-        // 35:上下闭合
-        // 36:上下对开
-        // 37;向右移动
-        // 38:向右连移
-        // 39:向下移动
-        // 40:向下连移
-        // 41:45度左旋
-        // 42:180度左旋
-        // 43:90度右旋
-        // 44:45度右旋
-        // 45:180度右旋
-        // 46:90度右旋
-        // 47:菱形打开
-        // 48:菱形闭合
-        DisplayStyle[] styles = DisplayStyleFactory.getStyles().toArray(new DisplayStyle[0]);
-
-        // 创建screen对象,用于与控制卡的交互
-        // 第二个参数是控制卡型号,只有型号对才能正常通讯,否则会出现逾时未回应,如果使用的型号API中未定义,用new Bx6M()替代
-        Bx6GScreenClient screen = new Bx6GScreenClient( "MyScreen",new Bx6E() );
-
-        // 连接控制器
-        screen.connect( ip,port);
-
-        // 创建节目 一个节目相当于一屏显示内容
-        ProgramBxFile pf = new ProgramBxFile( "P000",screen.getProfile() );
-
-        // 创建一个分区
-        // 分别输入X,Y,width,heigth
-        // 注意区域坐标和宽度高度不要越界
-        TextCaptionBxArea area = new TextCaptionBxArea( 0,0,160,64,screen.getProfile() );
-
-        // 创建一个数据页
-        // 第一行数据
-        TextBxPage page = new TextBxPage("仰邦科技欢迎你!");
-        // 第二行数据
-        page.newLine( "这是第二行数据" );
-        // 设置字体
-        page.setFont( new Font("宋体", Font.PLAIN,12) );
-        // 设置显示特技为快速打出
-        page.setDisplayStyle( styles[2] );
-
-        // 数据页可以是图片
-        ImageFileBxPage iPage  = new ImageFileBxPage( "D:a/004.bmp" );
-
-        // 数据页可以是txt文件
-        TextFileBxPage tPage = new TextFileBxPage( "D:a/001.txt" );
-
-        // 将前面的page添加到area中,page不可以是表格,如果需要Led显示表格,请先将表格绘制成图片
-        area.addPage( page );
-        area.addPage( iPage );
-        area.addPage( tPage );
-
-        // 将area添加到节目中,节目中可以添加多个area
-        pf.addArea( area );
-
-        // 更新节目
-        screen.writeProgram( pf );
-
-        // 断开连接
-        screen.disconnect();
-
-    }
-
-    // 将多个节目发送到控制器并显示
-    public static void SendPrograms()throws Exception
-    {
-        DisplayStyle[] styles = DisplayStyleFactory.getStyles().toArray(new DisplayStyle[0]);
-
-        Bx6GScreenClient screen = new Bx6GScreenClient( "MyScreen",new Bx6E() );
-
-        screen.connect( ip,port );
-
-        ProgramBxFile pf = new ProgramBxFile( "P000",screen.getProfile() );
-
-        // 创建一个时间区
-        DateTimeBxArea dtArea = new DateTimeBxArea( 0,0,160,64,screen.getProfile() );
-
-        // 设定时间区多行显示
-        dtArea.setMultiline( true );
-
-        // 设定日期显示格式 NULL表示不显示日期
-        dtArea.setDateStyle( DateStyle.YYYY_MM_DD_1 );
-        // 设定时间显示格式 NULL表示不显示时间
-        dtArea.setTimeStyle( TimeStyle.HH12_MM_SS_1 );
-        // 设定星期显示格式 NULL表示不显示星期
-        dtArea.setWeekStyle( WeekStyle.CHINESE );
-        // 设定时间区字体
-        dtArea.setFont( new Font("宋体",Font.PLAIN,12) );
-
-        pf.addArea( dtArea );
-
-        // 创建第二个节目
-        ProgramBxFile pf_2 = new ProgramBxFile( "P001",screen.getProfile() );
-        TextCaptionBxArea area = new TextCaptionBxArea( 0,0,160,64,screen.getProfile() );
-        TextBxPage page = new TextBxPage( "Led控制系统首选仰邦" );
-        page.setDisplayStyle( styles[4] );
-        area.addPage( page );
-        pf_2.addArea( area );
-
-        // 创建一个list
-        ArrayList<ProgramBxFile> plist = new ArrayList<ProgramBxFile>(  );
-        plist.add( pf );
-        plist.add( pf_2 );
-
-        screen.writePrograms( plist );
-
-        // 如果需要,可以从控制器回读控制器上已有的节目列表
-        List<String> pfs = screen.readProgramList();
-        for(String program:pfs)
-        {
-            System.out.println( program );
-        }
-
-        screen.disconnect();
-    }
-
-    // 更新动态区
-    // 六代卡中,只有BX-6E系列、BX-6EX系列和BX-6Q系列支持动态区
-    // 动态区是完全独立于节目,其显示内容可以按区域单独更新
-    // 动态区可以与节目一起播放,也可以单独播放
-    // 动态区显示内容存储于ARM,掉电不保存,没有刷新次数限制
-
-    // 动态区单独播放
-    public static void SendDynamic()throws Exception
-    {
-        DisplayStyle[] styles = DisplayStyleFactory.getStyles().toArray(new DisplayStyle[0]);
-
-        Bx6GScreenClient screen = new Bx6GScreenClient( "MyScreen",new Bx6E() );
-
-        screen.connect( ip,port );
-
-        // 创建动态区
-        // BX-6E BX-6EX系列支持4个动态区,BX-6Q系列支持32个动态区
-        DynamicBxAreaRule rule = new DynamicBxAreaRule();
-        // 设定动态区ID ,此处ID为0 ,多个动态区ID不能相同
-        rule.setId(0);
-        // 设定异步节目停止播放,仅播放动态区
-        // 0:与异步节目一起播放
-        // 1:异步节目 停止播放,仅播放动态区
-        // 2:当播放完节目编号坐高的异步节目后播放该动态区
-        rule.setImmediatePlay( (byte)1 );
-        // 设定动态区循环播放
-        // 0:循环显示
-        // 1:显示完成后静止显示最后一页数据
-        // 2:循环显示,超过设定时间后数据仍未更新时不再显示
-        // 3:循环显示,超过设定时间后数据仍未更新时显示Logo信息
-        // 4:循环显示,显示完成最后一页后就不再显示
-        rule.setRunMode( (byte)0 );
-
-        DynamicBxArea area = new DynamicBxArea( 0,0,160,32,screen.getProfile() );
-
-        TextBxPage page = new TextBxPage( "第一个动态区" );
-
-        page.setFont( new Font( "宋体",Font.PLAIN,12 ) );
-
-        page.setDisplayStyle( styles[2] );
-
-        area.addPage( page );
-
-        screen.writeDynamic( rule,area );
-
-        // 创建第二个动态区
-        DynamicBxAreaRule rule_2 = new DynamicBxAreaRule();
-        rule_2.setId( 1 );
-        rule_2.setImmediatePlay( (byte)1 );
-        rule_2.setRunMode( (byte)0 );
-        DynamicBxArea area_2 = new DynamicBxArea( 0,32,160,32,screen.getProfile() );
-        TextBxPage page_2 = new TextBxPage( "第二个动态区" );
-        page_2.setFont( new Font("宋体",Font.PLAIN,12) );
-        page_2.setDisplayStyle( styles[2] );
-        area_2.addPage( page_2 );
-        screen.writeDynamic( rule_2,area_2 );
-
-        screen.disconnect();
-    }
-
-
-
-    // 关于语音播报区域
-    // 语音播放目前只有六代部分卡支持
-    public static void SendSound()throws Exception
-    {
-        Bx6GScreenClient screen = new Bx6GScreenClient( "MyScreen",new Bx6E() );
-
-        screen.connect( ip,port );
-
-        DisplayStyle[] styles = DisplayStyleFactory.getStyles().toArray(new DisplayStyle[0]);
-
-        ProgramBxFile pf = new ProgramBxFile( "P000",screen.getProfile() );
-
-        // 语音部分
-        TextCaptionBxArea area_sound = new TextCaptionBxArea( 0,0,160,16,screen.getProfile());
-        area_sound.setVoiceContent( "黑A12345请到淀粉副产品库DF-01月台" );// 该字符串会被语音播报
-        area_sound.setVoiceFlag( true );
-        area_sound.setVoiceReplayTimes( 2 );// 设置重复播报3次,如果不设置,默认一直播报
-        // 语音的其他设置都在area_sound中设置
-
-        // 显示部分_1
-        TextCaptionBxArea area_display_1 = new TextCaptionBxArea( 0,0,160,48,screen.getProfile() );
-        TextBxPage page_display_1 = new TextBxPage( "黑A12345" );
-        page_display_1.setFont( new Font( "宋体",Font.PLAIN,30 ) );
-        page_display_1.setVerticalAlignment( TextBinary.Alignment.CENTER );// 设置水平居中
-        page_display_1.setHorizontalAlignment( TextBinary.Alignment.CENTER );// 设置垂直居中
-        page_display_1.setDisplayStyle( styles[2] );
-        area_display_1.addPage( page_display_1 );
-
-        // 显示部分_2
-        TextCaptionBxArea area_display_2 = new TextCaptionBxArea( 0,48,160,48,screen.getProfile() );
-        TextBxPage page_diaplay_2 = new TextBxPage( "请到淀粉副产品库" );
-        page_diaplay_2.newLine( "DF-01月台" );
-        page_diaplay_2.setFont( new Font( "宋体",Font.PLAIN,16 ) );
-        page_diaplay_2.setVerticalAlignment( TextBinary.Alignment.CENTER );
-        page_diaplay_2.setHorizontalAlignment( TextBinary.Alignment.CENTER );
-        page_diaplay_2.setDisplayStyle( styles[2] );
-        area_display_2.addPage( page_diaplay_2 );
-
-        pf.addArea( area_sound );
-        pf.addArea( area_display_1 );
-        pf.addArea( area_display_2 );
-
-        screen.writeProgram( pf );
-
-        screen.disconnect();
-    }
-
-    // 其他一些常用命令
-    public static void  SendCmd()throws Exception
-    {
-        Bx6GScreenClient screen = new Bx6GScreenClient( "MyScreen",new Bx6E() );
-        screen.connect( ip,port );
-        // 关机命令
-        screen.turnOff();
-        // 开机命令
-        screen.turnOn();
-        // ping命令
-        screen.ping();
-        // 查询控制器状态
-        screen.checkControllerStatus();
-        // 查询控制器内存
-        screen.checkMemVolumes();
-        // 校时命令
-        screen.syncTime();
-        // 锁定屏幕当前画面
-        screen.lock();
-        // 解除锁定屏幕当前画面
-        screen.unlock();
-        // 通过以下接口回读控制器状态
-        Bx6GScreen.Result<ReturnControllerStatus> result = screen.checkControllerStatus();
-        if(result.isOK())
-        {
-            ReturnControllerStatus status = result.reply;
-            status.getBrightness(); // 取得亮度值
-            status.getTemperature1(); // 取得温度传感器温度值
-            // status 还有很多接口,根据实际应用进行调用
-        }
-        else
-        {
-            ErrorType error = result.getError();
-            System.out.println( error );
-        }
-
-
-		// WindSpeed 字节数 2  风速(除以10为当前值)  0xffff时无效
-        // WindDirction 字节数 2 风向(当前值) 0xffff时无效
-        // PM2.5 字节数 2 PM2.5值(当前值) 0xffff时无效
-        // PM10 字节数 2 PM10值(当前值) 0xffff时无效
-        Bx6GScreenClient.Result<ReturnNetwork> result1 = screen.searchNetwork();
-        byte[] temp = result1.reply.getReserved1(); // 返回的前8个字节为上面注释里的定义
-        if(temp[1]*256+temp[0]!=0xffff)
-        {
-            System.out.println("风速:"+(temp[1]*256+temp[0])/10);
-        }
-        else
-        {
-            System.out.println("无数据");
-        }
-        if (temp[3]*256+temp[2]!=0xffff)
-        {
-            System.out.println("风向:"+(temp[3]*256+temp[2]));  //0:0°北风 1:45°东北风 2:90°东风 3:135°东南风 4:180°南风 5:225°西南风 6:270°西风 7:315°西北风
-        }
-        else
-        {
-            System.out.println("无数据");
-        }
-
-
-        System.out.println("保留字节:"+temp);
-    }
-
-    // 关于串口通讯
-    public static void RsConnect()throws Exception
-    {
-        // 串口创建screen对象  和网口不同
-        Bx6GScreenRS screen = new Bx6GScreenRS( "MyScreen",new Bx6E() );
-		// 串口创建screen对象,指定屏号 屏号范围0-255
-		Bx6GScreenRS screen_1 = new Bx6GScreenRS("MyScreen",new Bx6E(),(byte)0);
-        // 连接控制器  串口号必须大写,否则会出现连接失败
-        screen.connect( "COM2", Bx6GScreenRS.BaudRate.RATE_9600 );
-		screen_1.connect("COM3",Bx6GScreenRS.BaudRate.RATE_9600);
-        //
-        // 断开连接
-        screen.disconnect();
-    }
-	// 设置IO
-	public static void testSetIOState()throws Exception{
-        Bx6GScreenClient screen = new Bx6GScreenClient("myscreen",new Bx6E());
-        screen.connect(ip,port);
-        screen.setIOState(9,0);
-        screen.disconnect();
-    }
-	// 更新固件
-	private static byte[] toByteArray(String filePath)throws IOException{
-        InputStream inputStream = new FileInputStream(filePath);
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        byte[] bytes = new byte[1024*4];
-        int n = 0;
-        while((n = inputStream.read(bytes))!=-1){
-            baos.write(bytes,0,n);
-        }
-        inputStream.close();
-        return baos.toByteArray();
-    }
-    public static void updateFirmware()throws Exception{
-        byte[] data = toByteArray("BX-6E1X-V202201211.REL");
-        byte[] crc = new byte[2];
-        short file_crc = BxUtils.CRC16(data,0,data.length-2);
-        crc[0]=(byte)file_crc;
-        crc[1]=(byte)(file_crc>>8);
-        Bx6GScreenClient screen = new Bx6GScreenClient("screen",new Bx6E());
-        screen.connect(ip,port);
-        System.out.println("更新前固件" + screen.checkFirmware());
-        screen.writeFile("F001", FileType.FIRMWARE,data,crc);
-        screen.activateFirmware("F001");
-        Thread.sleep(10000);
-        System.out.println("更新后固件" + screen.checkFirmware());
-        screen.disconnect();
-    }*/
-}
diff --git a/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/controller/template/TemplateController.java b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/controller/template/TemplateController.java
new file mode 100644
index 0000000..996f485
--- /dev/null
+++ b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/controller/template/TemplateController.java
@@ -0,0 +1,56 @@
+package org.nl.system.controller.template;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import lombok.RequiredArgsConstructor;
+import org.nl.common.base.TableDataInfo;
+import org.nl.common.domain.query.PageQuery;
+import org.nl.common.logging.annotation.Log;
+import org.nl.system.service.template.TemplateService;
+import org.nl.system.service.template.dto.Template;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Map;
+
+@RestController
+@RequestMapping("/api/template")
+@RequiredArgsConstructor
+public class TemplateController {
+
+
+    @Autowired
+    private TemplateService templateService;
+
+    @PostMapping
+    @Log("添加模板")
+    public ResponseEntity<Object> add(@RequestBody Map map) {
+        boolean template_isNot = CollUtil.isNotEmpty(map);
+        if(!template_isNot || StrUtil.isEmpty((String) map.get("template_name"))){
+            throw new RuntimeException("模板名称不能为空");
+        }
+        templateService.addTemplate(map);
+        return new ResponseEntity<>(HttpStatus.OK);
+    }
+
+
+    @GetMapping("/id")
+    @Log("根据id查询模板")
+    public ResponseEntity<Object> getOne(@RequestParam String id) {
+        Template template = templateService.selectById(id);
+        JSONObject entries = JSONUtil.parseObj(templateService.selectById(id).getTemplate());
+        String printElements = entries.getStr("printElements");
+        template.setPrintElements(printElements);
+        return new ResponseEntity<>(template,HttpStatus.OK);
+    }
+
+    @GetMapping
+    @Log("查询模板")
+    public ResponseEntity<Object> queryAll(@RequestParam Map param, PageQuery page) {
+        return new ResponseEntity<>(TableDataInfo.build(templateService.query(param, page)),HttpStatus.OK);
+    }
+}
diff --git a/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/controller/tickets/TemplateController.java b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/controller/tickets/TemplateController.java
new file mode 100644
index 0000000..aeaaee9
--- /dev/null
+++ b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/controller/tickets/TemplateController.java
@@ -0,0 +1,60 @@
+/*
+package org.nl.system.controller.tickets;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.StrUtil;
+import lombok.RequiredArgsConstructor;
+import org.nl.common.base.TableDataInfo;
+import org.nl.common.domain.query.PageQuery;
+import org.nl.common.logging.annotation.Log;
+import org.nl.config.SpringContextHolder;
+import org.nl.system.service.tickets.TemplateService;
+import org.nl.system.service.tickets.dto.Template;
+import org.nl.system.service.tickets.impl.TemplateServiceImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Map;
+
+*/
+/**
+ * @author LENOVO
+ *//*
+
+@RestController
+@RequestMapping("/api/template")
+@RequiredArgsConstructor
+public class TemplateController {
+
+    TemplateService templateService = SpringContextHolder.getBean(TemplateService.class);
+
+    @PostMapping
+    @Log("添加模板")
+    private ResponseEntity<Object> add(@RequestBody Map map) {
+        boolean template_isNot = CollUtil.isNotEmpty(map);
+        if(!template_isNot || StrUtil.isEmpty((String) map.get("template_name"))){
+            throw new RuntimeException("模板名称不能为空");
+        }
+        templateService.addaTemplate(map);
+        return new ResponseEntity<>(HttpStatus.OK);
+    }
+
+
+    @GetMapping("/id")
+    @Log("根据id查询模板")
+    private ResponseEntity<Object> getOne(@RequestParam String id) {
+        Template template = templateService.selectById(id);
+        return new ResponseEntity<>(template,HttpStatus.OK);
+    }
+
+    @GetMapping
+    @Log("查询模板")
+    private ResponseEntity<Object> queryAll(@RequestParam Map param, PageQuery page) {
+        return new ResponseEntity<>(TableDataInfo.build(templateService.query(param, page)),HttpStatus.OK);
+    }
+
+
+}
+*/
diff --git a/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/controller/tickets/TicketsController.java b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/controller/tickets/TicketsController.java
index be47b46..0d84212 100644
--- a/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/controller/tickets/TicketsController.java
+++ b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/controller/tickets/TicketsController.java
@@ -4,6 +4,7 @@ import lombok.RequiredArgsConstructor;
 import org.nl.common.base.TableDataInfo;
 import org.nl.common.domain.query.PageQuery;
 import org.nl.common.logging.annotation.Log;
+import org.nl.system.service.template.TemplateService;
 import org.nl.system.service.tickets.TicketsService;
 import org.nl.system.service.tickets.dto.Tickets;
 import org.nl.system.service.tickets.dto.TicketsDto;
@@ -27,6 +28,9 @@ public class TicketsController {
     @Autowired
     private TicketsService ticketsService;
 
+    @Autowired
+    private TemplateService templateService;
+
     @Log("查询工单")
     @GetMapping
     public ResponseEntity<Object> queryAll(@RequestParam Map param, PageQuery page) {
diff --git a/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/service/template/TemplateService.java b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/service/template/TemplateService.java
new file mode 100644
index 0000000..d50f931
--- /dev/null
+++ b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/service/template/TemplateService.java
@@ -0,0 +1,20 @@
+package org.nl.system.service.template;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.nl.common.domain.query.PageQuery;
+import org.nl.system.service.template.dto.Template;
+
+import java.util.Map;
+
+public interface TemplateService extends IService<Template> {
+
+
+    void addTemplate(Map map);
+
+
+    Template selectById(String id);
+
+
+    IPage<Template> query(Map param, PageQuery page);
+}
diff --git a/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/service/template/dto/Template.java b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/service/template/dto/Template.java
new file mode 100644
index 0000000..87d6406
--- /dev/null
+++ b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/service/template/dto/Template.java
@@ -0,0 +1,57 @@
+package org.nl.system.service.template.dto;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@TableName("acs_template")
+public class Template {
+
+
+    /**
+     * 模板id
+     */
+    @TableId(type = IdType.NONE)
+    private String template_id;
+    /**
+     * 模板名称
+     */
+    private String template_name;
+    /**
+     * 模板状态
+     */
+    private String template_status;
+    /**
+     * 模板
+     */
+    private String template;
+    /**
+     * 创建人
+     */
+    private String create_by;
+
+    /**
+     * 创建时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private String create_time;
+    /**
+     * 修改人
+     */
+    private String update_by;
+    /**
+     * 修改时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private String update_time;
+
+    @TableField(value = "false")
+    private String printElements;
+
+}
diff --git a/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/service/template/dto/mapper/TemplateMapper.java b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/service/template/dto/mapper/TemplateMapper.java
new file mode 100644
index 0000000..ccb94e0
--- /dev/null
+++ b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/service/template/dto/mapper/TemplateMapper.java
@@ -0,0 +1,7 @@
+package org.nl.system.service.template.dto.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.nl.system.service.template.dto.Template;
+
+public interface TemplateMapper extends BaseMapper<Template> {
+}
diff --git a/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/service/template/impl/TemplateServiceImpl.java b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/service/template/impl/TemplateServiceImpl.java
new file mode 100644
index 0000000..8499683
--- /dev/null
+++ b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/service/template/impl/TemplateServiceImpl.java
@@ -0,0 +1,70 @@
+package org.nl.system.service.template.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.RandomUtil;
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.nl.common.domain.query.PageQuery;
+import org.nl.common.utils.SecurityUtils;
+import org.nl.system.service.template.TemplateService;
+import org.nl.system.service.template.dto.Template;
+import org.nl.system.service.template.dto.mapper.TemplateMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Service
+public class TemplateServiceImpl extends ServiceImpl<TemplateMapper, Template> implements TemplateService {
+
+
+    @Autowired
+    private TemplateMapper templateMapper;
+
+    @Override
+    public void addTemplate(Map map) {
+        String template_name =(String) map.get("template_name");
+        String panels1 = CollUtil.toList(map.get("panels")).get(0).toString();
+        String replace = panels1.replace("=", ":").substring(1, panels1.length() - 1);
+        Template template = new Template();
+        template.setTemplate_id(RandomUtil.randomNumbers(16));
+        template.setTemplate_name(template_name);
+        template.setTemplate(replace);
+        template.setCreate_by(SecurityUtils.getCurrentUsername());
+        template.setCreate_time(DateUtil.now());
+        template.setUpdate_by(SecurityUtils.getCurrentUsername());
+        template.setUpdate_time(DateUtil.now());
+        templateMapper.insert(template);
+    }
+
+    @Override
+    public Template selectById(String id) {
+        boolean id_isNot = StrUtil.isNotEmpty(id);
+        if(!id_isNot){
+            throw new RuntimeException("id不能为空");
+        }
+        Template template = templateMapper.selectById(id);
+        if(ObjectUtil.isEmpty(template)){
+            throw new RuntimeException("模板不存在");
+        }
+        return template;
+    }
+
+    @Override
+    public IPage<Template> query(Map param, PageQuery page) {
+        QueryWrapper<Template> wrapper = new QueryWrapper<>();
+        wrapper.like(ObjectUtil.isNotEmpty(param.get("template_name")),"template_name",0)
+                .eq(ObjectUtil.isNotEmpty(param.get("template_status")),"template_status",1)
+                .orderByAsc("create_time");
+        Page<Template> templatePage = this.page(new Page<>(page.getPage() + 1, page.getSize()), wrapper);
+        return templatePage;
+    }
+}
diff --git a/acs/nladmin-ui/package.json b/acs/nladmin-ui/package.json
index 833ea44..5381695 100644
--- a/acs/nladmin-ui/package.json
+++ b/acs/nladmin-ui/package.json
@@ -66,6 +66,8 @@
     "particles.js": "^2.0.0",
     "path-to-regexp": "2.4.0",
     "qrcode": "^1.5.3",
+    "qrcode-generator": "^1.4.4",
+    "qrcode.vue": "^3.4.1",
     "qrcodejs2": "0.0.2",
     "qs": "^6.9.1",
     "save": "^2.9.0",
@@ -74,6 +76,7 @@
     "tailwindcss": "^3.4.6",
     "throttle-debounce": "^5.0.0",
     "vue": "^2.6.10",
+    "vue-barcode": "^1.3.0",
     "vue-bus": "^1.2.1",
     "vue-color": "^2.8.1",
     "vue-count-to": "1.0.13",
@@ -85,6 +88,8 @@
     "vue-image-crop-upload": "^2.5.0",
     "vue-plugin-hiprint": "0.0.56",
     "vue-print-nb": "^1.7.5",
+    "vue-qrcode": "^2.2.2",
+    "vue-qrcode-reader": "^5.5.7",
     "vue-router": "3.0.2",
     "vue-seamless-scroll": "^1.1.23",
     "vue-splitpane": "1.0.4",
diff --git a/acs/nladmin-ui/src/api/acs/order/order.js b/acs/nladmin-ui/src/api/acs/order/order.js
index e427280..0e7ca33 100644
--- a/acs/nladmin-ui/src/api/acs/order/order.js
+++ b/acs/nladmin-ui/src/api/acs/order/order.js
@@ -26,7 +26,7 @@ export function edit(data) {
 
 export function query(id) {
   return request({
-    url: 'api/tickets/selectOne?id=' + id,
+    url: 'api/tickets/selectOne?id =' + id,
     method: 'get'
   })
 }
diff --git a/acs/nladmin-ui/src/api/acs/order/template.js b/acs/nladmin-ui/src/api/acs/order/template.js
new file mode 100644
index 0000000..977909b
--- /dev/null
+++ b/acs/nladmin-ui/src/api/acs/order/template.js
@@ -0,0 +1,18 @@
+import request from '@/utils/request'
+
+export function savePdf(data) {
+  return request({
+    url: 'api/template',
+    method: 'post',
+    data
+  })
+}
+
+export function see(id) {
+  return request({
+    url: 'api/template/id?id=' + id,
+    method: 'get'
+  })
+}
+
+export default { savePdf, see }
diff --git a/acs/nladmin-ui/src/views/acs/order/app.vue b/acs/nladmin-ui/src/views/acs/order/app.vue
new file mode 100644
index 0000000..0c34fc5
--- /dev/null
+++ b/acs/nladmin-ui/src/views/acs/order/app.vue
@@ -0,0 +1,190 @@
+<template>
+  <div class="app-container">
+    <div id="app" class="head-container">
+      <!-- <button @click="seeTemp">预览 </button> -->
+      <div v-if="crud.props.searchToggle">
+        <!-- 搜索 -->
+        <el-form
+          :inline="true"
+          class="demo-form-inline"
+          label-position="right"
+          label-suffix=":"
+        >
+          <el-form-item label="模板名称">
+            <el-input
+              v-model="query.template_name"
+              size="small"
+              placeholder="模板名称"
+              class="filter-item"
+              style="width: 200px"
+              @change="crud.toQuery"
+            />
+          </el-form-item>
+          <rrOperation />
+        </el-form>
+      </div>
+      <crudOperation :permission="permission">
+        <!-- <el-button
+          slot="left"
+          v-permission="['admin','task:add']"
+          class="filter-item"
+          size="mini"
+          type="primary"
+          icon="el-icon-plus"
+          @click="formDia=true"
+        >
+          {{ $t('auto.common.Create') }}
+        </el-button> -->
+      </crudOperation>
+      <div v-if="isModalVisible" class="modal" :style="{ width: modalWidth + 'px', height: modalHeight + 'px' }">
+        <button class="close-button" @click="hideModal">关闭</button>
+        <div v-for="element in printElements" :key="element.options.left + element.options.top" class="modal-content" :style="{position: 'absolute',left: element.options.left + 'px',top: element.options.top + 'px'}">
+          <div v-if="element.printElementType.type === 'table'">
+            <table border="1" :style="{width: element.options.width + 'px',height: element.options.height + 'px'}">
+              <thead>
+                <tr v-for="(row, rowIndex) in element.options.columns" :key="rowIndex">
+                  <th v-for="(col) in row" :key="col.field" :style="{ width: col.width + 'px' }">{{ col.title }}</th>
+                </tr>
+              </thead>
+              <tbody>
+                <!-- 这里填充表格内容 -->
+              </tbody>
+            </table>
+          </div>
+          <div v-else-if="element.printElementType.type === 'barcode'" :style="{ position: 'absolute', left: element.options.left + 'px', top: element.options.top + 'px' }">
+            <barcode :value="element.options.testData" :type="element.options.barcodeType" color="#000000" />
+          </div>
+
+          <div v-else-if="element.printElementType.type === 'qrcode'" :style="{ position: 'absolute', left: element.options.left + 'px', top: element.options.top + 'px' }">
+            <qrcode-vue :value="element.options.testData" :size="80" :color="{ dark: '#000000', light: '#ffffff' }" />
+          </div>
+
+          <div v-else-if="element.printElementType.type === 'text'">
+            <div v-if="element.options.title" :style="{ color: '#000000', display: 'inline' }">{{ element.options.title }}</div>
+            <div v-else>没有文本数据可显示</div>
+          </div>
+
+          <div v-else-if="element.printElementType.type === 'image'" :style="{ position: 'absolute', left: element.options.left + 'px', top: element.options.top + 'px' }">
+            <img :src="element.options.src" alt="Image" :width="element.options.width" :height="element.options.height">
+          </div>
+
+          <div v-else-if="element.printElementType.type === 'longText'">
+            <div v-if="element.options.title" :style="{ color: '#000000' }">{{ element.options.title }}</div>
+            <div v-else>没有文本数据可显示</div>
+          </div>
+        </div>
+      </div>
+      <el-table ref="table" v-loading="crud.loading" :data="crud.data" size="small" style="width: 100%;" @selection-change="crud.selectionChangeHandler">
+        <el-table-column type="selection" width="50px" />
+        <el-table-column v-if="false" prop="template_id" label="模板标识" />
+        <el-table-column prop="template_name" label="模板名称" :min-width="flexWidth('template_name',crud.data,'模板名称')" />
+        <el-table-column prop="template_status" label="模板状态" width="100px" />
+        <el-table-column prop="create_by" :label="$t('task.select.Creator')" :min-width="flexWidth('create_by',crud.data,$t('task.select.Creator'))" />
+        <el-table-column prop="create_time" :label="$t('task.select.Create_time')" :min-width="flexWidth('create_time',crud.data,$t('task.select.Create_time'))" />
+        <el-table-column v-permission="['admin','task:edit','task:del']" :label="$t('task.select.Operation')" width="80px" align="center" fixed="right">
+          <template slot-scope="scope">
+            <el-button
+              type="text"
+              icon="el-icon-edit"
+              @click="seeTemp(scope.row.template_id)"
+            >
+              修改
+            </el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <pagination />
+    </div>
+  </div>
+</template>
+
+<script>
+import Barcode from 'vue-barcode' // 确保安装了 vue-barcode
+// import Qrcode from 'vue-qrcode' // 确保安装了 vue-qrcode
+import QrcodeVue from 'qrcode.vue' // 确保安装了 vue-qrcode
+import template from '@/api/acs/order/template'
+import CRUD, { crud, header, presenter } from '@crud/crud'
+import crudOperation from '@crud/CRUD.operation'
+import rrOperation from '@crud/RR.operation'
+import pagination from '@crud/Pagination'
+
+export default {
+  components: {
+    'qrcode-vue': QrcodeVue,
+    Barcode,
+    crudOperation,
+    pagination,
+    rrOperation
+  },
+  mixins: [presenter(), header(), crud()],
+  cruds() {
+    return CRUD({ title: '模板', url: 'api/template', idField: 'template_id', sort: 'create_time,desc',
+      optShow: {
+        add: false,
+        edit: false,
+        del: true,
+        reset: false,
+        download: false
+      },
+      crudMethod: { ...template }})
+  },
+  data() {
+    return {
+      isModalVisible: false, // 控制弹框显示的状态
+      modalWidth: 800, // 弹框宽度
+      modalHeight: 600, // 弹框高度
+      printElements: [],
+      permission: {
+        add: ['admin', 'task:add'],
+        edit: ['admin', 'task:edit'],
+        del: ['admin', 'task:del']
+      }
+    }
+  },
+  computed: {
+    typeClass() {
+      return `type-${this.type}`
+    }
+  },
+  methods: {
+    seeTemp(id) {
+      template.see(id).then((data) => {
+        console.log('====================', data.printElements)
+        this.printElements = JSON.parse(data.printElements)
+        // 确保 data 对象中的 printElements 是数组
+        if (Array.isArray(this.printElements)) {
+          this.isModalVisible = true
+        } else {
+          console.error('data.printElements 不是数组')
+        }
+        console.log('====================', this.printElements)
+      }).catch(error => {
+        console.error('获取数据失败:', error)
+      })
+    },
+    hideModal() {
+      this.isModalVisible = false // 隐藏弹框
+    }
+  }
+}
+</script>
+
+<style>
+/* 添加一些样式来调节页面布局 */
+.modal {
+  position: fixed;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%, -50%);
+  background: white;
+  box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
+  z-index: 1000;
+  overflow: hidden; /* 处理溢出内容 */
+}
+
+.close-button {
+  position: absolute;
+  top: 10px;
+  right: 10px;
+}
+</style>
diff --git a/acs/nladmin-ui/src/views/acs/order/template.vue b/acs/nladmin-ui/src/views/acs/order/template.vue
index d11f4bb..2d9026b 100644
--- a/acs/nladmin-ui/src/views/acs/order/template.vue
+++ b/acs/nladmin-ui/src/views/acs/order/template.vue
@@ -5,6 +5,12 @@
         <i class="iconfont sv-printer" />
         浏览器打印
       </button>
+      <!-- <button class="secondary circle-10 ml-10" @click.stop="getHtml">
+        <i class="iconfont sv-preview" />
+        预览
+      </button> -->
+      <el-button type="primary" @click="PreviewData"> 导出 </el-button>
+      <el-button type="primary" @click="addTable"> 保存 </el-button>
       <!-- <button class="warning circle-10 ml-10" @click.stop="print2">
         直接打印(需要连接客户端)
         <i class="iconfont sv-printer" />
@@ -30,12 +36,12 @@
             <i class="iconfont sv-table" />
             <span>表格</span>
           </div>
-          <div class="ep-draggable-item item" tid="defaultModule.html">
-            <i class="iconfont sv-html" />
+          <div class="ep-draggable-item item" tid="defaultModule.qrcode">
+            <i class="iconfont sv-qrcode" />
             <span>html</span>
           </div>
-          <div class="ep-draggable-item item" tid="defaultModule.customText">
-            <i class="iconfont sv-text" />
+          <div class="ep-draggable-item item" tid="defaultModule.barcode">
+            <i class="iconfont sv-barcode" />
             <span>自定义</span>
           </div>
           <div class="title">辅助元素</div>
@@ -66,25 +72,60 @@
         <div id="PrintElementOptionSetting" />
       </div>
     </div>
+    <div>
+      <el-dialog :close-on-click-modal="false" :visible.sync="formDias" title="模板" width="550px">
+        <el-form ref="form" :model="form" :rules="rules" size="small" label-width="110px">
+          <el-row>
+            <el-col :span="24">
+              <div class="grid-content bg-purple" />
+              <el-form-item label="模板名称" prop="template_name">
+                <el-input v-model="form.template_name" style="width: 370px;" @change="isDisabled=false" />
+              </el-form-item>
+              <el-form-item label="模板状态" prop="template_status">
+                <el-input v-model="form.template_status" style="width: 370px;" @change="isDisabled=false" />
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </el-form>
+        <div slot="footer" class="dialog-footer">
+          <el-button type="primary" @click="formDias=false">{{ $t('task.select.Cancel') }}</el-button>
+          <el-button :disabled="isDisabled" type="primary" @click="editBtn">{{ $t('task.select.Confirm') }}</el-button>
+        </div>
+      </el-dialog>
+    </div>
   </div>
 </template>
 
 <script>
 import $ from 'jquery'
 import { hiprint, defaultElementTypeProvider } from 'vue-plugin-hiprint'
+import template from '@/api/acs/order/template'
 
 // 初始化 provider
 hiprint.init({
   providers: [defaultElementTypeProvider()]
 })
-
 export default {
   name: 'Hrprint',
   data() {
     return {
-      hiprintTemplate: null // 声明 hiprintTemplate 以便在 buildDesigner 中使用
+      formDias: false,
+      hiprintTemplate: null, // 声明 hiprintTemplate 以便在 buildDesigner 中使用
+      printResults: [],
+      isDisabled: false,
+      form: {
+        template_name: '',
+        template_status: '',
+        template: Object
+      },
+      rules: {
+        template_name: [
+          { required: true, message: '模板名称不能为空', trigger: 'blur' }
+        ]
+      }
     }
   },
+
   mounted() {
     // 确保 hiprint 初始化完成后再执行构建操作
     this.$nextTick(() => {
@@ -93,6 +134,10 @@ export default {
     })
   },
   methods: {
+    addTable() {
+      this.formDias = true
+      this.isDisabled = false
+    },
     /**
      * 构建左侧可拖拽元素
      * 注意: 可拖拽元素必须在 hiprint.init() 之后调用
@@ -158,6 +203,44 @@ export default {
       } else {
         alert('请先连接客户端(刷新网页), 然后再点击「直接打印」')
       }
+    },
+    PreviewData() {
+      this.hiprintTemplate.toPdf('', '').then((tempPrintResults) => {
+        // 处理生成的 PDF 数据
+        console.log('获取pdf结果::::' + tempPrintResults)
+
+        // 创建 Blob 对象
+        const blob = new Blob([tempPrintResults], { type: 'application/pdf' })
+        const url = URL.createObjectURL(blob)
+
+        // 创建下载链接并设置文件名
+        const link = document.createElement('a')
+        link.href = url
+        link.download = 'your-custom-file-name.pdf' // 设置文件名
+        document.body.appendChild(link) // 追加到 DOM 中
+        link.click() // 触发下载
+        document.body.removeChild(link) // 下载后移除链接
+
+        // 清理 URL 对象
+        URL.revokeObjectURL(url)
+      }).catch((error) => {
+        console.error('PDF 生成失败:', error)
+      })
+    },
+    editBtn() {
+      // console.log('保存数据', this.hiprintTemplate.getJson())
+      this.isDisabled = true
+      this.form = {
+        ...this.form, // 保留原有属性
+        ...this.hiprintTemplate.getJson() // 赋值新属性
+      }
+      template.savePdf(this.form).then((data) => {
+        this.formDias = false
+        // 设置定时器,等待一定时间后再次允许请求
+        setTimeout(() => {
+          this.isDisabled = false // 可根据具体需求进行调整
+        }, 1000) // 5000 毫秒,即 5 秒钟
+      })
     }
   }
 }