Browse Source

Merge branch 'qingban' of http://192.168.101.4:3000/jiaxiaoqiang/JG-ADMIN-TEMP into qingban

qinhb 10 tháng trước cách đây
mục cha
commit
eb5ab39f76

+ 2 - 0
package.json

@@ -55,10 +55,12 @@
     "element-plus": "^2.6.0",
     "exceljs": "^4.4.0",
     "file-saver": "^2.0.5",
+    "fs": "0.0.1-security",
     "html-to-image": "^1.11.11",
     "html2canvas": "^1.4.1",
     "lodash-es": "^4.17.21",
     "luckyexcel": "^1.0.1",
+    "nanoid": "^5.0.7",
     "net": "^1.0.2",
     "nprogress": "^0.2.0",
     "path-browserify": "^1.0.1",

+ 3 - 0
public/version.json

@@ -0,0 +1,3 @@
+{
+  "version": "24.7.15.v1"
+}

+ 8 - 0
src/api/excel/index.ts

@@ -86,3 +86,11 @@ export function deleteSettingsData(data: any) {
     data,
   });
 }
+//生产履历修改EXcell数据(实际为新增)
+export function setExcelData(data: any) {
+  return request({
+    url: "/api/v1/ProcessFormData/add",
+    method: "post",
+    data,
+  });
+}

+ 4 - 1
src/components/ExcelView/index.vue

@@ -17,7 +17,9 @@
           </template>
         </el-upload>
       </div>
-      <div class="info">当前操作表格:{{ inName == "" ? "-" : inName }}</div>
+      <div class="info" v-if="option.opreaTitle">
+        当前操作表格:{{ inName == "" ? "-" : inName }}
+      </div>
     </div>
   </div>
   <div
@@ -56,6 +58,7 @@ const props = defineProps({
       print: true,
       edit: true,
       inName: "",
+      opreaTitle: true,
     }),
   },
 });

+ 2 - 1
src/plugins/permission.ts

@@ -2,7 +2,7 @@ import router from "@/router";
 import { useUserStore } from "@/store/modules/user";
 import { usePermissionStore } from "@/store/modules/permission";
 import { useDictionaryStore } from "@/store/modules/dictionary";
-
+import { isNewVersion } from "@/utils/version.js";
 import NProgress from "@/utils/nprogress";
 import { getUserDicts } from "@/api/auth";
 
@@ -12,6 +12,7 @@ export function setupPermission() {
 
   router.beforeEach(async (to, from, next) => {
     NProgress.start();
+    isNewVersion();
     const hasToken = localStorage.getItem("token");
     if (hasToken) {
       if (to.path === "/login") {

+ 40 - 0
src/utils/version.js

@@ -0,0 +1,40 @@
+// utils/version.js
+
+import axios from "axios";
+// 生成一个随机的字符串作为请求的查询参数
+import { nanoid } from "nanoid";
+import { ElMessageBox } from "element-plus";
+
+export async function isNewVersion() {
+  // 构建了一个 URL,用于请求版本信息的 JSON 文件。这个 URL 包括当前页面的主机名和一个随机生成的长度为 10 的字符串作为查询参数。
+  const url = `//${window.location.host}/version.json?id=${nanoid(10)}`;
+  // 使用 Axios 发起了一个 get 请求,获取版本信息的 json 文件。
+  try {
+    const res = await axios.get(url);
+    //   从响应数据中获取了版本号。
+    const version = res.data.version;
+    //   从本地存储中获取了之前保存的版本号
+    const localVersion = localStorage.getItem("version");
+    //   检查本地存储的版本号是否存在且与当前版本号不一致
+    if (localVersion && localVersion !== version) {
+      ElMessageBox.confirm("发现新的版本,请刷新页面后使用!", "系统提示", {
+        confirmButtonText: "立即刷新",
+        // cancelButtonText: this.$t('btn.cancel'),
+        showCancelButton: false,
+        closeOnClickModal: false,
+        type: "warning",
+      })
+        .then(() => {
+          localStorage.setItem("version", version);
+          window.location.reload();
+        })
+        .catch(() => {});
+    } else {
+      // 如果没有发现新版本,则仅将当前版本号保存到本地存储中。
+      // 这段代码的作用是在页面加载时检查是否有新版本可用,如果有新版本则重新加载页面以获取最新版本
+      localStorage.setItem("version", version);
+    }
+  } catch (error) {
+    console.log(error);
+  }
+}

+ 0 - 1
src/views/pro/traceability/components/equitCom.vue

@@ -135,7 +135,6 @@ option.value = Object.assign(option.value, {
         label: "dictLabel",
         value: "dictValue",
       },
-
     },
     {
       label: "精度要求",

+ 167 - 0
src/views/pro/traceability/components/excelCom.vue

@@ -0,0 +1,167 @@
+<!-- 表格数据 -->
+<template>
+  <div class="mainContentBox">
+    <avue-crud
+      ref="crudRef2"
+      v-model:search="search"
+      v-model="form"
+      @row-update="createRow"
+      :data="data"
+      :option="option"
+      v-model:page="page"
+    >
+      <template #menu="{ size, row, index }">
+        <el-button
+          v-if="row.excelData != '' && row.excelData != null"
+          link
+          size="small"
+          type="primary"
+          @click="opView(row)"
+          style="margin: 0"
+          ><i-ep-view />查看
+        </el-button>
+        <el-button
+          v-if="row.excelData != '' && row.excelData != null"
+          type="warning"
+          link
+          size="small"
+          @click="opUpdate(row)"
+          style="margin: 0"
+          ><i-ep-edit />修改表格数据
+        </el-button>
+      </template>
+    </avue-crud>
+    <el-dialog
+      v-model="updataShow"
+      :title="updateTitle"
+      @close="updataShow = false"
+      width="1600"
+    >
+      <updateExcel
+        @refresh="refreshDatalist"
+        :data="ExData"
+        @close="closeShow"
+      />
+    </el-dialog>
+  </div>
+</template>
+<script setup>
+import { ref, getCurrentInstance } from "vue";
+import { useCrud } from "@/hooks/userCrud";
+import dictDataUtil from "@/common/configs/dictDataUtil";
+import ButtonPermKeys from "@/common/configs/buttonPermission";
+import {
+  useCommonStoreHook,
+  useDictionaryStore,
+  useUserStoreHook,
+} from "@/store";
+import updateExcel from "./updateExcel.vue";
+// 数据字典相关
+const { dicts } = useDictionaryStore();
+const updataShow = ref(false);
+const updateTitle = ref("修改表格数据");
+const crudRef2 = ref({});
+const lookStatus = ref(false);
+const opUpdate = (row) => {
+  ExData.value = row;
+  ExData.value.lookStatus = false;
+  updataShow.value = true;
+};
+const opView = (row) => {
+  ExData.value = row;
+  ExData.value.lookStatus = true;
+  updataShow.value = true;
+};
+const closeShow = () => {
+  updataShow.value = false;
+};
+const ExData = ref("");
+// 传入一个url,后面不带/
+const {
+  form,
+  data,
+  option,
+  search,
+  page,
+  toDeleteIds,
+  Methords,
+  Utils,
+  commonConfig,
+} = useCrud({
+  src: "/api/v1/ProcessFormData",
+});
+const ctableRef = ref(null);
+const { dataList, createRow, updateRow, deleteRow, searchChange, resetChange } =
+  Methords; //增删改查
+const { selectionChange, multipleDelete } = Methords; //选中和批量删除事件
+const { checkBtnPerm, downloadTemplate, exportData } = Utils; //按钮权限等工具
+const userStore = useUserStoreHook();
+const crudRef = ref(null); //crudRef.value 获取avue-crud对象
+const doEdit = (row, index) => {
+  crudRef2.value && crudRef2.value.rowEdit(row, index);
+};
+const refreshTra = (row) => {
+  commonConfig.value.params = { seqNo: row.seqNo };
+  dataList();
+};
+const refreshDatalist = () => {
+  dataList();
+};
+defineExpose({ refreshTra });
+onMounted(() => {
+  if (userStore.user.userId === 10000) {
+    option.value.menu = true;
+  }
+});
+
+option.value = Object.assign(option.value, {
+  selection: false,
+  border: true,
+  index: false,
+  expandLevel: 3,
+  headerAlign: "center",
+  align: "center",
+  labelWidth: 100,
+  addBtn: false,
+  delBtn: false,
+  viewBtn: false,
+  menu: false,
+  header: false,
+  editBtn: false,
+  rowKey: "operationId",
+  column: [
+    {
+      label: "工序Id",
+      prop: "operationId",
+      display: false,
+      hide: true,
+    },
+    {
+      label: "工序名称",
+      prop: "operationName",
+      disabled: true,
+      search: false,
+      display: false,
+    },
+
+    {
+      label: "表格名称",
+      disabled: true,
+      prop: "formName",
+      search: false,
+    },
+    {
+      label: "表格类型",
+      prop: "formType",
+      type: "select",
+      disabled: true,
+      search: false,
+      dicData: dicts.excel_type,
+      props: {
+        label: "dictLabel",
+        value: "dictValue",
+      },
+    },
+  ],
+});
+</script>

+ 1 - 1
src/views/pro/traceability/components/mediaCom.vue

@@ -1,4 +1,4 @@
-<!-- 报故记录 -->
+<!-- 图片采集 -->
 <template>
   <div class="mainContentBox">
     <img src="" />

+ 14 - 13
src/views/pro/traceability/components/recordCom.vue

@@ -12,14 +12,12 @@
     >
       <template #menu="{ size, row, index }">
         <el-button
-            v-if="
-            row.label!=undefined && row.label!=null
-          "
-            type="primary"
-            link
-            size="small"
-            @click="doEdit(row,index)"
-        ><i-ep-edit />编辑
+          v-if="row.label != undefined && row.label != null"
+          type="primary"
+          link
+          size="small"
+          @click="doEdit(row, index)"
+          ><i-ep-edit />编辑
         </el-button>
       </template>
     </avue-crud>
@@ -30,7 +28,11 @@ import { ref, getCurrentInstance } from "vue";
 import { useCrud } from "@/hooks/userCrud";
 import dictDataUtil from "@/common/configs/dictDataUtil";
 import ButtonPermKeys from "@/common/configs/buttonPermission";
-import {useCommonStoreHook, useDictionaryStore, useUserStoreHook} from "@/store";
+import {
+  useCommonStoreHook,
+  useDictionaryStore,
+  useUserStoreHook,
+} from "@/store";
 
 // 数据字典相关
 const { dicts } = useDictionaryStore();
@@ -63,10 +65,9 @@ const refreshTra = (row) => {
 defineExpose({ refreshTra });
 const userStore = useUserStoreHook();
 onMounted(() => {
-  if(userStore.user.userId===10000){
+  if (userStore.user.userId === 10000) {
     option.value.menu = true;
   }
-
 });
 const doEdit = (row, index) => {
   crudRef2.value && crudRef2.value.rowEdit(row, index);
@@ -126,8 +127,8 @@ option.value = Object.assign(option.value, {
     {
       label: "录入时间",
       prop: "created",
-      format: 'YYYY-MM-DD HH:mm:ss',
-      valueFormat: 'YYYY-MM-DD HH:mm:ss',
+      format: "YYYY-MM-DD HH:mm:ss",
+      valueFormat: "YYYY-MM-DD HH:mm:ss",
       type: "datetime",
       search: false,
       span: 24,

+ 353 - 0
src/views/pro/traceability/components/updateExcel.vue

@@ -0,0 +1,353 @@
+<template>
+  <div class="dialogBody">
+    <div class="exView" :key="excelKey1">
+      <ExcelView
+        ref="excelViewRef"
+        :option="options"
+        @confirm="confirm"
+        v-model:data="exceldata"
+      />
+    </div>
+    <div class="btns" v-if="options.edit !== false">
+      <el-button class="btn" type="success" @click="submit">确 定 </el-button>
+      <el-button class="btn" @click="reset">重 置 </el-button>
+      <el-button class="btn" type="info" @click="cancel">取 消 </el-button>
+    </div>
+    <div class="btns" v-else>
+      <el-button class="btn" type="info" @click="cancel">返 回 </el-button>
+    </div>
+  </div>
+</template>
+<script setup lang="ts">
+import { ref } from "vue";
+import { useCrud } from "@/hooks/userCrud";
+import { setExcelData } from "@/api/excel/index.ts";
+import ExcelView from "@/components/ExcelView/index.vue";
+import { useDictionaryStore } from "@/store";
+const props = defineProps({
+  data: {
+    type: Object,
+  },
+});
+const rowData = ref({});
+const emits = defineEmits(["update:modelValue", "close", "refresh"]);
+const excelKey1 = ref(false);
+const submit = async () => {
+  excelViewRef.value.confirm();
+  const { data, code } = await setExcelData({
+    excelData: JSON.stringify(exceldata.value),
+    excelFormId: rowData.value.excelFormId,
+    processId: rowData.value.processId,
+    formType: rowData.value.formType,
+    formName: rowData.value.formName,
+  });
+  if (code == "200") {
+    ElMessage.success("修改成功!");
+    cancel();
+    emits("refresh");
+  }
+};
+const reset = () => {
+  exceldata.value = JSON.parse(rowData.value.excelData);
+  excelKey1.value = !excelKey1.value;
+};
+const cancel = () => {
+  excelKey1.value = !excelKey1.value;
+  options.value.edit = true;
+  emits("close");
+};
+// 存放操作表格相关业务代码
+const useAddTemplateHook = () => {
+  //excelView 组件实例
+  const excelViewRef = ref(null);
+  //表格配置项
+  const options = ref({
+    //头部操作区域
+    opreaState: true,
+    //导入按钮展示
+    in: true,
+    //导出按钮展示
+    out: false,
+    print: true,
+    //编辑状态 false:为查看状态
+    edit: true,
+    //当前操作表格名称
+    inName: "",
+    opreaTitle: false,
+  });
+  //双向绑定表格data变量
+  const exceldata = ref(null);
+  //控制表格组件展示界面变量(包括表格展示页面和操作页面)
+  const excelStatus = ref(true);
+
+  //获取组件内实时数据赋值到外层
+  const confirm = (data: any) => {
+    exceldata.value = data;
+  };
+  return {
+    excelStatus,
+    options,
+    confirm,
+    exceldata,
+    excelViewRef,
+  };
+};
+const { options, confirm, exceldata, excelViewRef } = useAddTemplateHook();
+const useFormHook = () => {
+  //KEY告知组件刷新
+  const excelKey = ref(1);
+  //表单data
+  const formVlaue = reactive({ formType: null, formName: null, state: null });
+  //表单是否为编辑状态变量
+  const operaEditStatus = ref(false);
+  //选中的行id
+  const selectId = ref(null);
+  //表单ref实例
+  const formRef = ref(null);
+  //表单校验规则
+  const rules = reactive({
+    formName: [
+      {
+        required: true,
+        trigger: "blur",
+      },
+    ],
+    formType: [
+      {
+        required: true,
+        trigger: "blur",
+      },
+    ],
+    state: [
+      {
+        required: true,
+        trigger: "blur",
+      },
+    ],
+  });
+  //新增模版
+  const submitForm = async (formEl: any) => {
+    //@ts-ignore;
+    excelViewRef.value.confirm();
+    if (exceldata.value == null) return ElMessage.error("请提供表格数据!");
+    if (!formEl) return;
+    await formEl.validate(async (valid: any, fields: any) => {
+      if (valid) {
+        const { data, code } = await addExcel({
+          ...formVlaue,
+          excelData: exceldata.value,
+        });
+        if (code == "200") {
+          ElMessage.success("添加成功!");
+          resetData();
+          dataEditList();
+          editTep(data);
+        }
+      }
+    });
+  };
+  //更新行内信息
+  const updateExForm = async (formEl: any) => {
+    //@ts-ignore;
+    excelViewRef.value.saveCellData();
+    //@ts-ignore;
+    excelViewRef.value.confirm();
+    if (exceldata.value == null) return ElMessage.error("请提供表格数据!");
+    if (!formEl) return;
+    await formEl.validate(async (valid: any, fields: any) => {
+      if (valid) {
+        const { data, code } = await updateExcel({
+          ...formVlaue,
+          excelData: exceldata.value,
+          id: selectId.value,
+          settings: settings.value,
+        });
+        if (code == "200") {
+          ElMessage.success("修改成功!");
+          resetData();
+          dataEditList();
+        }
+      }
+    });
+  };
+  //表达数据重置
+  const resetForm = (formEl: any) => {
+    if (!formEl) return;
+    formEl.resetFields();
+  };
+  return {
+    formVlaue,
+    formRef,
+    rules,
+    selectId,
+    excelKey,
+    operaEditStatus,
+    submitForm,
+    resetForm,
+    updateExForm,
+  };
+};
+
+const {
+  formVlaue,
+  formRef,
+  rules,
+  selectId,
+  excelKey,
+  operaEditStatus,
+  submitForm,
+  resetForm,
+  updateExForm,
+} = useFormHook();
+//表格新增 分页
+const useAddFormHook = () => {
+  const formRef1 = ref(null);
+  const settings = ref([]);
+  const searchForm = ref({
+    pageNo: 1,
+    pageSize: 5,
+    totalPages: 0,
+  });
+  const addForm = ref({
+    paramName: "",
+    position: "",
+  });
+  const addPage = () => {
+    searchForm.value.pageNo = searchForm.value.pageNo + 1;
+    getSettingData();
+  };
+  const deletePage = () => {
+    searchForm.value.pageNo = searchForm.value.pageNo - 1;
+    getSettingData();
+  };
+  const getSettingData = async () => {
+    const { data } = await getSettingsData({
+      excelFormId: selectId.value,
+      ...searchForm.value,
+    });
+    settings.value = data.records;
+    if (settings.value.length == 0 && searchForm.value.pageNo > 1) {
+      deletePage();
+    }
+    searchForm.value.totalPages = data.totalPages;
+  };
+  const addSettings = async () => {
+    const { data, code } = await addSettingsData({
+      excelFormId: selectId.value,
+      ...addForm.value,
+    });
+    if (code == "200") {
+      ElMessage.success("添加成功");
+      resetAddForm();
+      getSettingData();
+    }
+  };
+  const deleteSettings = async (id: any) => {
+    const { data, code } = await deleteSettingsData({ id: id });
+    if (code == "200") {
+      ElMessage.success("删除成功");
+      getSettingData();
+    }
+  };
+
+  const resetAddForm = () => {
+    addForm.value = {
+      paramName: "",
+      position: "",
+    };
+    searchForm.value = {
+      pageNo: 1,
+      pageSize: 5,
+      totalPages: 0,
+    };
+    settings.value = [];
+  };
+  const creatAddForm = async () => {
+    await formRef1.value.validate(async (valid: any, fields: any) => {
+      if (valid) {
+        addSettings();
+      }
+    });
+  };
+  const addRules = reactive({
+    paramName: [
+      {
+        required: true,
+        trigger: "blur",
+      },
+    ],
+    position: [
+      {
+        required: true,
+        trigger: "blur",
+      },
+    ],
+  });
+  return {
+    formRef1,
+    addForm,
+    searchForm,
+    settings,
+    addRules,
+    creatAddForm,
+    resetAddForm,
+    getSettingData,
+    addSettings,
+    addPage,
+    deleteSettings,
+    deletePage,
+  };
+};
+
+const {
+  formRef1,
+  addForm,
+  searchForm,
+  settings,
+  addRules,
+  creatAddForm,
+  deletePage,
+  addPage,
+  resetAddForm,
+  getSettingData,
+  deleteSettings,
+} = useAddFormHook();
+watch(
+  () => props.data,
+  () => {
+    //@ts-ignore
+    rowData.value = props.data;
+    exceldata.value = JSON.parse(rowData.value.writeData);
+    excelKey1.value = !excelKey1.value;
+    if (rowData.value.lookStatus == true) {
+      options.value.edit = false;
+    }
+  },
+  { immediate: true }
+);
+</script>
+<style lang="scss" scoped>
+.dialogBody {
+  width: 1560px;
+  height: 560px;
+  display: flex;
+  .exView {
+    width: 1330px;
+    height: 560px;
+    display: flex;
+    position: relative;
+  }
+  .btns {
+    width: 200px;
+    height: 560px;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    padding: 40px 0 0 20px;
+    .btn {
+      width: 100%;
+      margin: 10px;
+    }
+  }
+}
+</style>

+ 30 - 11
src/views/pro/traceability/index.vue

@@ -56,11 +56,11 @@
             <el-tab-pane name="traceabilityComRef" label="生产履历">
               <template #label>
                 <span
-                >生产履历
+                  >生产履历
                   <el-badge
-                      :value="tabCount.traceability"
-                      class="item"
-                      type="primary"
+                    :value="tabCount.traceability"
+                    class="item"
+                    type="primary"
                   />
                 </span>
               </template>
@@ -131,19 +131,33 @@
               </template>
               <FaultCom ref="faultComRef" />
             </el-tab-pane>
-<!--            <el-tab-pane name="bugComRef" label="缺陷项">缺陷项</el-tab-pane>-->
+            <!--            <el-tab-pane name="bugComRef" label="缺陷项">缺陷项</el-tab-pane>-->
             <el-tab-pane name="mediaComRef" label="图片采集"
               ><template #label>
                 <span
-                >图片采集
+                  >图片采集
                   <el-badge
-                      :value="tabCount.medias"
-                      class="item"
-                      type="primary"
+                    :value="tabCount.medias"
+                    class="item"
+                    type="primary"
                   />
                 </span>
-            </template>
-            <media-com ref="mediaComRef"/></el-tab-pane>
+              </template>
+              <media-com ref="mediaComRef"
+            /></el-tab-pane>
+            <el-tab-pane name="excelComRef" label="表格数据"
+              ><template #label>
+                <span
+                  >表格数据
+                  <el-badge
+                    :value="tabCount.excel"
+                    class="item"
+                    type="primary"
+                  />
+                </span>
+              </template>
+              <ExcelCom ref="excelComRef"
+            /></el-tab-pane>
           </el-tabs>
         </el-main>
       </el-container>
@@ -162,6 +176,7 @@ import CheckCom from "@/views/pro/traceability/components/checkCom.vue";
 import EquitCom from "@/views/pro/traceability/components/equitCom.vue";
 import FaultCom from "@/views/pro/traceability/components/faultCom.vue";
 import MediaCom from "./components/mediaCom.vue";
+import ExcelCom from "./components/excelCom.vue";
 
 // 传入一个url,后面不带/
 const { form, data, option, search, page, toDeleteIds, Methords, Utils } =
@@ -182,6 +197,7 @@ const checkComRef = ref(null);
 const equitComRef = ref(null);
 const faultComRef = ref(null);
 const mediaComRef = ref(null);
+const excelComRef = ref(null);
 let defaultTabName = ref("traceabilityComRef");
 //tab页组件
 const tabNameComRef = new Map([
@@ -192,10 +208,12 @@ const tabNameComRef = new Map([
   ["equitComRef", equitComRef],
   ["faultComRef", faultComRef],
   ["mediaComRef", mediaComRef],
+  ["excelComRef", excelComRef],
 ]);
 let temRow = ref({});
 const tabsEvent = (pane, ev) => {
   defaultTabName.value = pane.props.name;
+  console.log(pane.props.name, temRow.value.seqNo);
   if (temRow.value.seqNo) {
     tabNameComRef.get(pane.props.name)?.value.refreshTra(temRow.value);
   }
@@ -237,6 +255,7 @@ let tabCount = reactive({
   equit: "",
   fault: "",
   medias: "",
+  excel: "",
 });
 
 const handleCellClick = (row, column, event) => {

+ 28 - 0
vite.config.ts

@@ -133,6 +133,7 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
         // 指定symbolId格式
         symbolId: "icon-[dir]-[name]",
       }),
+      process.env.NODE_ENV === "production" && updateVersion(),
     ],
     // 预加载项目必需的组件
     optimizeDeps: {
@@ -252,3 +253,30 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
     },
   };
 });
+// 打包文件时候 更新版本号 用作判断是否要刷新页面
+function updateVersion() {
+  console.log("upVer");
+  const fs = require("fs");
+  return {
+    name: "update-version",
+    buildStart() {
+      let version = "";
+      try {
+        // 读取 json 文件里面版本号
+        const packageJson = JSON.parse(
+          fs.readFileSync("public/version.json", "utf-8")
+        );
+        version = Number(packageJson.version);
+        version = (version + 0.1).toFixed(1); // 增加0.1并保留1位小数
+      } catch (error) {
+        console.log(error);
+      }
+      const versionData = { version: version.toString() }; // 根据需要生成新版本号
+      // 写入 json 文件里面版本号
+      fs.writeFileSync(
+        "public/version.json",
+        JSON.stringify(versionData, null, 2)
+      );
+    },
+  };
+}