lvhao 2 horas atrás
pai
commit
367d661356

+ 61 - 0
core/CoreApp/controllers/Goodimglibrary.php

@@ -21,6 +21,8 @@ class Goodimglibrary extends Start_Controller {
             $this->_getInfoNumber();
         }elseif($arg == 'showsku'){
             $this->_showSku($arg_array);
+        }elseif($arg == 'bcedit'){
+            $this->_bcedit($arg_array);
         }else{
 			$this->_index();
 		}
@@ -277,6 +279,65 @@ class Goodimglibrary extends Start_Controller {
             
         }
     }
+
+    private function _bcedit($arg_array){
+        if($this->input->method() == 'post'){
+            $id = $this->input->post('id',true);
+            $img = $this->input->post('img',true);
+            if(empty($img)){
+                $img = [];
+            }
+            foreach($img as $k => $v){
+                $img[$k] = str_replace($this->show_url, '', $v);
+            }
+            $info  =  $this->db->get_where('crowd_goods',array('id'=>$id))->row_array();    
+            $images = $this->goodimgs->find("goods_id = ".$id);
+            $has_source = empty($img)?0:5;
+            $update_time = time();
+            if(empty($images)){
+                if($this->goodimgs->insert(array('goods_id'=>$id,'features'=>$info['features'],'source_cont'=>json_encode($img,JSON_UNESCAPED_SLASHES)))){
+                    $this->goods->save(array('has_source'=>$has_source,'update_time'=>$update_time),$id);
+                    echo json_encode(array('msg'=>'修改成功','success'=>true));exit;
+                }else{
+                    echo json_encode(array('msg'=>'修改失败,请重试1','success'=>false));exit;
+                }
+
+            }else{
+                if($this->goodimgs->save(array('features'=>$info['features'],'source_cont'=>json_encode($img,JSON_UNESCAPED_SLASHES)),$images['id'])){
+                    $this->goods->save(array('has_source'=>$has_source,'update_time'=>$update_time),$id);
+                    echo json_encode(array('msg'=>'修改成功','success'=>true));exit;
+                }else{
+                    echo json_encode(array('msg'=>'修改失败,请重试3','success'=>false));exit;
+                }
+            }
+
+        }
+        if($this->input->method() == 'get'){
+            $id = $arg_array[0];
+            $goods = $this->db->get_where('crowd_goods',array('id'=>$id))->row_array();
+            $this->db->where('goods_id',$id);
+            $images = $this->db->get('crowd_goodimgs')->result_array();
+            if(empty($images)){
+                $goods['images'] = [];
+            }else{
+                $imgs = json_decode($images[0]['source_cont'],true);
+                $final_imgs = [];
+                foreach($imgs as $k => $v){
+                    $final_imgs[$k]['url'] = $this->_transingurl($v);
+                    $final_imgs[$k]['type'] = $this->_checkVideo($v);
+                }
+                $goods['images'] = $final_imgs;
+            }
+           
+           
+            $this->data['goods'] = $goods;
+            $this->_Template('goodimglibrary_bcedit',$this->data);
+            
+        }
+    }
+
+
+
     //根据后缀判断是否是视频
     private function _checkVideo($str){
         $hz_arr = explode(".",$str);

+ 6 - 3
template/erp/goodimglibrary.html

@@ -28,6 +28,8 @@ dialog::backdrop {
   color: white;
   cursor: pointer;
 }
+
+
   
 </style>
 <body>
@@ -79,10 +81,11 @@ dialog::backdrop {
 <li>商品名称:<input value="" name="title" type="text" style="width:350px"></li>
 <li>仓库品名:<input value="" name="zh" type="text" style="width:350px"></li>
 <li><span>确 定</span></li>
-</ul>
-<!-- <div class="control">
 
-</div> -->
+</ul>
+<div class="control">
+  <a href="javascript:void(0);" class="window" data-h="/goodimglibrary/get_info_number/" data-t="订单编码添加图片">订单编码添加图片</a>
+</div>
 <table class="datatitle data" border="0" style="border-collapse:collapse;">
 <tr>
 <td><label onClick="swapCheck()"><input name="checkbox" type="checkbox" class="regular-checkbox"></label></td>

+ 592 - 0
template/erp/goodimglibrary_bcedit.html

@@ -0,0 +1,592 @@
+{Template header}
+
+<style>
+   input[type="file"] {
+        display: none;
+    }
+     /* 图片网格 */
+     .image-grid {
+        display: grid;
+        grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
+        gap: 1.2rem;
+        margin-top: 1rem;
+    }
+    .image-card {
+        position: relative;
+        background: #f1f5f9;
+        border-radius: 20px;
+        overflow: hidden;
+        box-shadow: 0 4px 8px rgba(0,0,0,0.05);
+        transition: transform 0.2s, box-shadow 0.2s;
+    }
+    .image-card:hover {
+        transform: translateY(-4px);
+        box-shadow: 0 12px 20px -8px rgba(0,0,0,0.2);
+    }
+    .image-card img {
+        width: 100%;
+        aspect-ratio: 1 / 1;
+        object-fit: cover;
+        display: block;
+        background: #e2e8f0;
+    }
+    .delete-btn {
+        position: absolute;
+        top: 8px;
+        right: 8px;
+        background: rgba(0,0,0,0.65);
+        backdrop-filter: blur(4px);
+        border: none;
+        color: white;
+        width: 28px;
+        height: 28px;
+        border-radius: 40px;
+        font-size: 16px;
+        font-weight: bold;
+        cursor: pointer;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        transition: 0.2s;
+        font-family: monospace;
+    }
+    .delete-btn:hover {
+        background: #dc2626;
+        transform: scale(1.05);
+    }
+    .upload-status {
+        margin-top: 0.8rem;
+        font-size: 0.85rem;
+        color: #2563eb;
+        display: flex;
+        align-items: center;
+        gap: 6px;
+    }
+    .loading-spinner {
+        width: 16px;
+        height: 16px;
+        border: 2px solid #bfdbfe;
+        border-top-color: #2563eb;
+        border-radius: 50%;
+        animation: spin 0.7s linear infinite;
+        display: inline-block;
+    }
+    @keyframes spin {
+        to { transform: rotate(360deg); }
+    }
+    hr {
+        margin: 1.5rem 0;
+        border: none;
+        border-top: 1px solid #e2e8f0;
+    }
+    .info-note {
+        background: #fef9c3;
+        color: #854d0e;
+        font-size: 0.8rem;
+        padding: 0.6rem 1rem;
+        border-radius: 20px;
+        margin-top: 1rem;
+    }
+    button {
+        background: none;
+        border: none;
+    }
+    .btn-outline {
+        background: white;
+        border: 1px solid #cbd5e1;
+        padding: 0.4rem 1rem;
+        border-radius: 40px;
+        font-size: 0.8rem;
+        cursor: pointer;
+    }
+
+
+/* 锁定背景页面滚动,防止弹窗出现时背景页还能滚动 */
+body.lock-scroll {
+  overflow: hidden;
+}
+
+/* 设置对话框背景遮罩 */
+dialog::backdrop {
+  background: rgba(0, 0, 0, 0.8);
+}
+
+/* 确保放大后的图片不会超出视口 */
+#dialog-img {
+  max-width: 90vw;
+  max-height: 90vh;
+  display: block;
+}
+
+/* 关闭按钮样式 */
+#close-btn {
+  position: absolute;
+  top: 10px;
+  right: 15px;
+  font-size: 24px;
+  background: none;
+  border: none;
+  color: white;
+  cursor: pointer;
+}
+
+
+</style>
+<body>
+<div class="warp">
+<div class="title winnone">货品图片 - 编辑</div>
+<ul class="setting">
+
+
+
+<li class="length">
+<em>SKU:</em>
+<b>{$goods['sku']}</b>
+</li>
+<li class="length">
+<em>商品名称:</em>
+<b>{$goods['title']}</b>
+</li>
+<li class="length">
+<em>仓库名称:</em>
+<b>{$goods['zh']}</b>
+</li>
+<li class="length">
+<em>料号:</em>
+<b>{$goods['jm']}</b>
+</li>
+
+<li class="length">
+  <em>上传图片/视频</em>
+  <span>
+    <a href="javascript:void(0);" id = "upload-btn"><span style="background-color: #2ca8a1;padding:4px 10px;color:#fff;border-radius: 3px;font-size: 16px;"> <span>点击添加图片/视频</span></span> </a>
+   
+    <input type="file" id="fileInput" accept="image/jpeg,image/png,image/gif,image/webp,image/avif,image/bmp,image/svg+xml,image/tiff,video/mp4,video/webm,video/ogg,video/quicktime,video/x-msvideo,video/3gpp" multiple>
+  </span>
+  
+  
+<!-- 状态显示区 (上传中) -->
+<div id="statusMsg" class="upload-status" style="min-height: 32px;"></div>
+<!-- 图片列表展示区 -->
+<div id="imageGallery" class="image-grid">
+    {foreach $goods['images'] as $img}
+        {if $img['type'] == 'video'}
+            <div class="image-card">
+                <video controls="true" width="150" src="{$img['url']}" alt="video image"></video>
+                <input type="hidden" name="img[]" value="{$img['url']}" />
+                <button class="delete-btn" onclick="del(this)">✕</button>
+            </div>
+
+        {else}
+            <div class="image-card">
+                <img src="{$img['url']}" alt="uploaded image" onclick="showImg(this)">
+                <input type="hidden" name="img[]" value="{$img['url']}" />
+                <button class="delete-btn" aria-label="删除文件" onclick="del(this)">✕</button>
+            </div>
+        {/if}
+    
+    {/foreach}
+</div>
+
+
+
+<div style="clear:both;"></div>
+</ul>
+
+<input type="hidden" name="id" value="{$goods['id']}" />
+<div class="button"><font class="bcsave">提 交</font> <font class="fh">关 闭</font></div>
+</div>
+<!-- 对话框元素,默认是隐藏的 -->
+<dialog id="image-dialog" role="dialog" aria-modal="true">
+<img id="dialog-img" src="" alt="">
+<button id="close-btn">×</button>
+</dialog>
+
+<script>
+
+var addedit="/goodimglibrary/bcedit/";
+const  uploadZone = document.getElementById("upload-btn");
+const fileInput = document.getElementById('fileInput');
+const statusDiv = document.getElementById('statusMsg');
+const gallery = document.getElementById('imageGallery');
+
+// 向oss上传文件
+async function uploadSingleFile(file, credentials, onProgress) {
+    return new Promise(async (resolve, reject) => {
+        // 生成最终存储路径:目录 + 时间戳 + 随机数 + 原文件名
+        const timestamp = Date.now();
+        const random = Math.floor(Math.random() * 10000);
+        const safeName = `${timestamp}_${random}_${file.name.replace(/\s/g, '_')}`;
+        const objectKey = credentials.dir + safeName;
+
+        // 初始化 OSS 客户端
+        const client = new OSS({
+            region: credentials.region,
+            accessKeyId: credentials.accessKeyId,
+            accessKeySecret: credentials.accessKeySecret,
+            stsToken: credentials.stsToken,
+            bucket: credentials.bucket,
+            secure: true   // 使用 HTTPS
+        });
+
+        try {
+            // 使用分片上传(适合大文件,小文件也会自动处理)
+            const result = await client.multipartUpload(objectKey, file, {
+                progress: (p, checkpoint) => {
+                    const percent = Math.floor(p * 100);
+                    onProgress(percent);
+                }
+            });
+            // 拼接完整的访问 URL
+            //const fileUrl = `https://${credentials.bucket}.${credentials.region}.aliyuncs.com/${objectKey}`;
+            const fileUrl = credentials.show_url+'/'+transf_img_url(`${objectKey}`);
+            resolve(fileUrl);
+        } catch (err) {
+            reject(err);
+        }
+    });
+}
+// 显示短暂状态消息
+function showStatus(text, isLoading = false) {
+    if (!statusDiv) return;
+    if (isLoading) {
+        statusDiv.innerHTML = `<span class="loading-spinner"></span><span>${text}</span>`;
+    } else {
+        statusDiv.innerHTML = `<span>✅ ${text}</span>`;
+        setTimeout(() => {
+            if (statusDiv.innerHTML.includes(text)) {
+                statusDiv.innerHTML = '';
+            }
+        }, 2000);
+    }
+}
+
+// 添加图片卡片到画廊
+function addImageToGallery(imageUrl, fileName = '',fileType='') {
+    const card = document.createElement('div');
+    card.className = 'image-card';
+    let img ;
+    // 存储图片URL以便释放 (对于base64无需revoke,但如果是blob URL需要,这里base64无内存问题)
+    if (fileType.includes('image')) {
+        img = document.createElement('img');
+        img.src = imageUrl;
+        img.alt = fileName || 'uploaded image';
+        img.onclick = function() {
+            showImg(this);  // this 指向 img
+        };
+    } else {
+        img = document.createElement('video');
+        img.src = imageUrl;
+        img.controls = true;
+        img.alt = fileName || 'uploaded video';
+        img.width="150"
+    }
+   
+   
+    
+    const delBtn = document.createElement('button');
+    delBtn.innerHTML = '✕';
+    delBtn.className = 'delete-btn';
+    delBtn.setAttribute('aria-label', '删除图片');
+    
+    // 删除事件
+    delBtn.onclick = function() {
+        del(this);  // this 指向 delBtn
+    };
+    const input = document.createElement('input');
+    input.type = 'hidden';
+    input.name = 'img[]';
+    input.value = imageUrl;
+    
+    card.appendChild(img);
+    card.appendChild(input);
+    card.appendChild(delBtn);
+    gallery.appendChild(card);
+}
+
+// 1. 从后端获取上传凭证(STS 临时授权参数)
+async function getUploadCredentials() {
+    const response = await fetch('/aliyuntp/get_oss_sign');  // 替换成你的后端接口地址
+    if (!response.ok) throw new Error('获取上传凭证失败');
+    const data = await response.json();
+    // 后端需返回: { region, accessKeyId, accessKeySecret, stsToken, bucket, dir }
+    return data;
+}
+
+
+// 处理文件上传的核心流程
+async function handleFiles(files) {
+    if (!files || files.length === 0) return;
+
+    // 获取后端凭证
+    let res = await getUploadCredentials();
+    let credentials = res.data
+    
+    // 遍历所有选择的文件(支持多选)
+    for (let i = 0; i < files.length; i++) {
+        const file = files[i];
+        // 显示每张图片的上传状态(可以统一显示)
+        showStatus(`正在上传: ${file.name}...`, true);
+        const fileId = `upload_${Date.now()}_${i}`;
+        try {
+            //获取上传凭证 
+            const imgDataUrl = await uploadSingleFile(file,credentials, (percent) => {
+                    updateProgress(fileId, percent);
+                });
+            // 上传成功,添加到页面
+            addImageToGallery(imgDataUrl, file.name,file.type);
+            showStatus(`${file.name} 上传成功!`, false);
+        } catch (err) {
+            console.error(err);
+            showStatus(`${file.name} 失败: ${err.message}`, false);
+            // 错误提示2秒后恢复
+            setTimeout(() => {
+                if (statusDiv.innerText.includes(file.name)) statusDiv.innerHTML = '';
+            }, 2500);
+        }
+    }
+    // 清空 input 的值,允许重复上传同一个文件
+    fileInput.value = '';
+    // 最后清空上传中状态如果没有更多任务
+    setTimeout(() => {
+        if (statusDiv.innerHTML.includes('正在上传') === false && statusDiv.innerHTML !== '') {
+            // 保留最后一条成功提示但2秒后已经清空,不做额外处理
+        }
+    }, 500);
+}
+
+function updateProgress(fileId, percent) {
+    console.log(`{$fileId}上传进度: ${percent}%`);
+    // const fill = document.getElementById(`progress-${fileId}`);
+    // if (fill) fill.style.width = percent + '%';
+}
+// 点击上传区域触发文件选择
+uploadZone.addEventListener('click', (e) => {
+    // 防止点到内部冒泡导致重复触发
+    if (e.target === uploadZone || uploadZone.contains(e.target)) {
+        fileInput.click();
+    }
+});
+
+// 文件选择变化时触发上传
+fileInput.addEventListener('change', (e) => {
+    const files = e.target.files;
+    if (files.length) {
+        handleFiles(files);
+    }
+});
+
+// 阻止拖拽默认事件 (让拖拽体验更好, 可选)
+uploadZone.addEventListener('dragover', (e) => {
+    e.preventDefault();
+    uploadZone.style.borderColor = '#3b82f6';
+    uploadZone.style.background = '#eff6ff';
+});
+uploadZone.addEventListener('dragleave', (e) => {
+    e.preventDefault();
+    uploadZone.style.borderColor = '#cbd5e1';
+    uploadZone.style.background = '#f8fafc';
+});
+uploadZone.addEventListener('drop', (e) => {
+    e.preventDefault();
+    uploadZone.style.borderColor = '#cbd5e1';
+    uploadZone.style.background = '#f8fafc';
+    const files = e.dataTransfer.files;
+    if (files.length) {
+        handleFiles(files);
+    }
+});
+
+function del(that){
+    console.log("123");
+    $(that).closest(".image-card").remove();  
+}
+
+
+function transf_img_url(url){
+    let url_arr = url.split('/');
+    let filename = url_arr.pop();               // 取出文件名
+    filename = encodeURIComponent(filename);    // 对文件名进行 URL 编码
+    url_arr.push(filename);                     // 将编码后的文件名放回数组
+    let final_url = url_arr.join('/'); 
+    return final_url;
+}
+
+
+
+const dialog = document.getElementById('image-dialog');
+const dialogImg = document.getElementById('dialog-img');
+const closeBtn = document.getElementById('close-btn');
+
+// 点击图片,打开对话框
+// img.addEventListener('click', () => {
+//   console.log(img)
+//   dialogImg.src = img.data('ulr'); // 将缩略图的src赋给对话框中的图片
+//   dialog.showModal();      // 显示对话框
+// });
+function showImg(that) {
+    dialogImg.src = $(that).attr('src'); // 将缩略图的src赋给对话框中的图片
+    dialog.showModal();      // 显示对话框
+}
+
+
+// 点击关闭按钮,关闭对话框
+closeBtn.addEventListener('click', () => {
+  dialog.close();
+});
+
+// 点击对话框的遮罩层(非图片区域),也可以关闭
+dialog.addEventListener('click', (e) => {
+  if (e.target === dialog) {
+    dialog.close();
+  }
+});
+
+// 监听对话框的打开和关闭事件,用于锁定和恢复背景页滚动
+dialog.addEventListener('show', () => {
+  document.body.classList.add('lock-scroll');
+});
+dialog.addEventListener('close', () => {
+  document.body.classList.remove('lock-scroll');
+});
+</script>
+<script>
+$(".bcsave").click(function() {
+	$(".ts p").html("<i class='fa fa-2x fa-cog fa-spin'></i> &nbsp; 正在添加中,请稍后...");
+        $(".ts").show();
+    var f = "";
+    var e = "";
+    $(".select").each(function() {
+        f = f + $(this).attr("name") + "=" + $(this).children("option:selected").val() + "&";
+    });
+    $("input:text").each(function() {
+       str2 = $(this).val().replace(/\</g,"&lt;");
+		str2 = str2.replace(/\>/g,"&gt;");
+		str2 = str2.replace(/\+/g,"%2B");
+		str2 = str2.replace(/&/g,"%26");
+        f = f + $(this).attr("name") + "=" + str2 + "&";
+    });
+	$("input:password").each(function() {
+        f = f + $(this).attr("name") + "=" + $(this).val() + "&";
+    });
+    $("input:hidden").each(function() {
+        f = f + $(this).attr("name") + "=" + $(this).val() + "&";
+    });
+
+    if($("#content").length > 0)
+	{
+		var vl = $("#content").html().replace(/\+/g,"%2B");
+        vl = vl.replace(/\&/g,"%26");
+        f = f + "content=" + encodeURI(vl) + "&";
+ }
+
+	$("textarea").each(function() {
+		var str2 = $(this).val().replace(/\+/g,"%2B");
+		var str2 = str2.replace(/&/g,"%26");
+        f = f + $(this).attr("name") + "=" + str2 + "&";
+    });
+	if($(".scimg img").length > 0 || $(".scimg video").length > 0)
+	{
+		var a = '';
+		 for (var b = 0; b < $(".scimg .upimg img").length; b++) 
+		 {
+        a = a + $(".scimg .upimg img")[b].src + "|";
+        }
+		for (var b = 0; b < $(".scimg .upimg video").length; b++) 
+		 {
+        a = a + $('.scimg .upimg video')[b].src + "|";
+        }
+		var a = a.replace(/\+/g,"%2B");
+		var a = a.replace(/&/g,"%26");
+		 f = f + "img=" + a + "&";
+	}
+	if($(".scimg_two img").length > 0 || $(".scimg_two video").length > 0)
+	{
+		var a = '';
+			for (var b = 0; b < $(".scimg_two .upimg_two img").length; b++) 
+			{
+		a = a + $(".scimg_two .upimg_two img")[b].src + "|";
+		}
+		for (var b = 0; b < $(".scimg_two .upimg_two video").length; b++) 
+			{
+		a = a + $('.scimg_two .upimg_two video')[b].src + "|";
+		}
+		var a = a.replace(/\+/g,"%2B");
+		var a = a.replace(/&/g,"%26");
+			f = f + "img_two=" + a + "&";
+	}
+	for(i=0;i<$(".checkbox").length;i++)
+	{
+		var checkid = ""; var checkname = "";
+    $(".checkbox:eq("+i+") .ckrows input:checked").each(function(){
+		 checkname = $(this).attr("name");
+             checkid = checkid + $(this).val()+",";
+    });
+	 if(checkname == "")
+	 {
+		 $(".ts p").text($(".checkbox:eq("+i+")").prevAll("em").text()+"为必填项");
+        $(".ts").show();
+        setTimeout('$(".ts").fadeOut()', 600);
+        return false;
+	 }
+	 f = f + checkname + "=" + checkid + "&";
+		
+	}
+	
+	for(i=0;i<$(".checkboxfbt").length;i++)
+	{
+		var checkid = ""; var checkname = "";
+    $(".checkboxfbt:eq("+i+") .ckrows input:checked").each(function(){
+		 checkname = $(this).attr("name");
+             checkid = checkid + $(this).val()+",";
+    });
+	 if(checkname != "")
+	 {
+		 f = f + checkname + "=" + checkid + "&";
+	 }
+		
+	}
+    var ab = 0;
+    $(".must").each(function() {
+        if ($.trim($(this).val()).length == 0) {
+            $(this).css("border", "1px solid #F66");
+            ab = ab + 1;
+        }
+    });
+    if (ab > 0) {
+        $(".ts p").text("红框为必填项");
+        $(".ts").show();
+        setTimeout('$(".ts").fadeOut()', 600);
+        return false;
+    }
+    $.ajax({
+        url: addedit,
+        data: f,
+        type: "POST",
+        dataType: "json",
+        success: function(a) {
+            if (a && a.success) {
+				$(".ts").hide();
+                $(".express p:eq(0)").html(a.msg+"是否关闭?");
+				$(".express p:eq(1)").html("<font onclick='close_door()' class='esc'>确 定</font>");
+                $(".express").show();
+            } else {
+				$(".ts").hide();
+                $(".ts p").html(a.msg);
+                $(".ts").fadeIn();
+                setTimeout('$(".ts").fadeOut()', 800);
+            }
+        }
+    });
+});
+
+
+function close_door(){
+    $(".express").hide();
+    $(".fh").click();
+}
+
+</script>
+<script type="text/javascript" src="{$theme}js/aliyun-oss-sdk-6.20.0.min.js"></script>
+<script type="text/javascript" src="{$theme}js/ajaxupload.3.5.js"></script>
+{Template footer}

+ 2 - 2
template/erp/goodimglibrary_number.html

@@ -30,7 +30,7 @@
 </div>
 <script>
 var scwd = "/fullorderexcel/scwd";
-var addedit="/returns/edit/";
+var addedit="/returns/bcedit/";
 
 function searchInfo(){
     var number = $('#number').val();
@@ -81,7 +81,7 @@ function showTable(data){
             <td style="width: 30%;"><%= data[key]['sku'] %><br> <%= data[key]['features']  %></td>
             <td style="width: 30%;"><%= data[key]['zh'] %></td>
             <td style="width: 30%;"><%= data[key]['title'] %></td>
-            <td style="width: 5%;"><a href="javascript:void(0);" class="window add_lv_btn" data-h="/goodimglibrary/edit/<%= data[key]['s_id'] %>" data-t="货品图片-编辑">添 加</a></td>
+            <td style="width: 5%;"><a href="javascript:void(0);" class="window add_lv_btn" data-h="/goodimglibrary/bcedit/<%= data[key]['s_id'] %>" data-t="货品图片-编辑">添 加</a></td>
         </tr>
     <% } %>
 </table>