Ver código fonte

项目管理所属项目的开发

wsx 11 meses atrás
pai
commit
ac46be1143

+ 1 - 0
.gitignore

@@ -23,3 +23,4 @@ yarn-error.log*
 *.sw?
 vue.config.js
 package-lock.json
+vue.config.js

+ 95 - 0
src/components/linkParentDialog/components/search.vue

@@ -0,0 +1,95 @@
+<!-- 搜索表单 -->
+<template>
+  <el-form
+    size="small"
+    label-width="80px"
+    class="ele-form-search"
+    @keyup.enter.native="search"
+    @submit.native.prevent
+  >
+    <el-row :gutter="10">
+      <el-col v-bind="styleResponsive ? { md: 6 } : { span: 6 }">
+        <el-form-item label="项目编码">
+          <el-input
+            clearable
+            size="small"
+            v-model="where.code"
+            placeholder="请输入"
+          />
+        </el-form-item>
+      </el-col>
+      <el-col v-bind="styleResponsive ? { md: 6 } : { span: 6 }">
+        <el-form-item label="项目名称">
+          <el-input
+            clearable
+            size="small"
+            v-model="where.name"
+            placeholder="请输入"
+          />
+        </el-form-item>
+      </el-col>
+      <el-col style="display: flex;justify-content: flex-end" v-bind="styleResponsive ? { md: 12 } : { span: 12 }">
+        <el-form-item>
+          <el-button
+            size="small"
+            type="primary"
+            icon="el-icon-search"
+            class="ele-btn-icon"
+            @click="search"
+          >
+            查询
+          </el-button>
+
+          <el-button
+            @click="reset"
+            icon="el-icon-refresh"
+            class="ele-btn-icon"
+            size="medium"
+          >重置
+          </el-button
+          >
+          <slot></slot>
+        </el-form-item>
+      </el-col>
+
+
+    </el-row>
+
+  </el-form>
+</template>
+
+<script>
+export default {
+  data() {
+    // 默认表单数据
+    const defaultWhere = {
+      name: '',
+      code: ''
+    };
+    return {
+      defaultWhere,
+      // 表单数据
+      where: {...defaultWhere},
+      loading: false
+    };
+  },
+  computed: {
+    // 是否开启响应式布局
+    styleResponsive() {
+      return this.$store.state.theme.styleResponsive;
+    }
+  },
+  methods: {
+    /* 搜索 */
+    search() {
+      this.$emit('search', this.where);
+    },
+    /*  重置 */
+    reset() {
+      this.where = {...this.defaultWhere};
+      this.search();
+    },
+
+  }
+};
+</script>

+ 16 - 64
src/components/linkParentDialog/components/tree.vue

@@ -4,7 +4,7 @@
       :data="treeList"
       :props="defaultProps"
       v-loading="treeLoading"
-      :node-key="nodeKey"
+      node-key="id"
       ref="tree"
       :highlight-current="true"
       :expand-on-click-node="false"
@@ -64,11 +64,15 @@
       nodeKey: {
         type: String,
         default: 'id'
-      }
+      },
       // appendRoot: {
       //   type: Boolean,
       //   default: false
       // },
+      pid: {
+        type: String,
+        default: ''
+      }
     },
     data() {
       return {
@@ -79,73 +83,21 @@
         currentKey: ''
       };
     },
+    created() {},
     mounted() {
-      if (this.init) {
-        // this.getTreeData();
-      }
+      this.$nextTick(() => {
+        let id=(this._props.pid);
+        console.log(id);
+        this.$nextTick(()=>{
+          this.$refs.tree.setCurrentKey(id);
+        })
+      });
     },
     methods: {
-      getInstance() {
-        return this.$refs.tree;
-      },
-      // 获取树结构数据
-    //   async getTreeData(params = {}) {
-    //     try {
-    //       this.treeLoading = true;
-
-    //       const data = await listOrganizations(params);
-    //       this.treeLoading = false;
-    //       this.$emit('setRootId', data[0].id);
-    //       this.treeList = this.$util.toTreeData({
-    //         data: data || [],
-    //         idField: 'id',
-    //         parentIdField: 'parentId'
-    //       });
-    //       this.$nextTick(() => {
-    //         // 默认高亮第一级树节点
-    //         if (this.treeList[0] && this.isFirstRefreshTable) {
-    //           this.setCurrentKey(this.treeList[0].id);
-    //           this.handleNodeClick(
-    //             this.treeList[0],
-    //             this.$refs.tree.getCurrentNode()
-    //           );
-    //         }
-    //       });
-    //       return this.treeList;
-    //     } catch (error) {
-    //       console.error(error);
-    //     }
-    //     this.treeLoading = false;
-    //   },
-      // 递归 - 往树children里面添加parentName
-      // _setParentName (tree) {
-      //   let data = tree;
-      //   for (let i = 0; i < data.length; i++) {
-      //     if (data[i].parentId === '0') {
-      //       this.parentName = data[i].name;
-      //       originId = data[i].id;
-      //       originType = data[i].type;
-      //     }
-
-      //     data[i]['originId'] = originId;
-      //     data[i]['originType'] = originType;
-      //     data[i]['parentId'] = data[i]['parentId'];
-      //     if (data[i].children && data[i].children.length > 0) {
-      //       this._setParentName(data[i].children);
-      //     }
-      //   }
-      //   return data;
-      // },
-
       handleNodeClick(data, node) {
-        this.$emit('handleNodeClick', data, node);
-      },
-      // 设置默认高亮行
-      setCurrentKey(id) {
-        this.currentKey = id;
-        this.$refs.tree.setCurrentKey(this.currentKey);
+        console.log(data);
+        this.$emit('handleNodeClick', { ...data });
       },
-
       // 获取树的选中状态
       getSelectList() {
         const selectList = this.$refs.tree.getCurrentNode();

+ 280 - 16
src/components/linkParentDialog/index.vue

@@ -11,7 +11,7 @@
   >
     <el-card shadow="never">
       <ele-split-layout
-        width="244px"
+        width="200px"
         allow-collapse
         :right-style="{ overflow: 'hidden' }"
       >
@@ -21,21 +21,20 @@
             :isFirstRefreshTable="false"
             ref="treeListRef"
             :treeList="treeList"
+            :pid="parentId"
           />
         </div>
         <!-- 表格 -->
         <template v-slot:content>
-          <user-select-search @search="reload"></user-select-search>
+          <search @search="reload"></search>
           <ele-pro-table
             ref="table"
-            :columns="columns"
+            :columns="tableColumns"
             :datasource="datasource"
             row-key="id"
             height="calc(100vh - 430px)"
             class="dict-table"
             @cell-click="cellClick"
-            cache-key="systemRoleTable3"
-            :selection.sync="selection"
           >
             <!-- 表头工具栏 -->
             <template v-slot:action="{ row }">
@@ -57,17 +56,23 @@
 
 <script>
   // import DepartmentTree from '@/components/departmentTree';
+  import { contactPage } from '@/api/custom';
   import tree from './components/tree.vue';
+  import search from './components/search.vue';
   import selectPersonDialog from '@/BIZComponents/user-select/user-select.vue';
-  import userSelectSearch from '@/BIZComponents/user-select/user-select-search.vue';
 
+  // import userSelectSearch from '@/BIZComponents/user-select/user-select-search.vue';
+  import { getByCode } from '@/api/system/dictionary-data';
+  import { projectsPageAPI } from '@/api/project-manage';
+  import { reviewStatusEnum } from '@/enum/dict';
   export default {
     components: {
       tree,
       selectPersonDialog,
-      userSelectSearch
+      search
     },
     props: {
+      parentId: { default: '', type: String },
       linkParentDialogFlag: {
         type: Boolean,
         default: false
@@ -96,30 +101,289 @@
       return {
         title: '关联项目',
         selection: [],
-        columns: [],
-        treeList: []
+        // columns: [],
+        treeList: [],
+        rootId: '',
+        params: {
+          type: ''
+        },
+        tableColumns: [
+          {
+            action: 'action',
+            slot: 'action',
+            align: 'center',
+            label: '选择'
+          },
+          {
+            columnKey: 'index',
+            label: '序号',
+            type: 'index',
+            width: 55,
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'typeName',
+            label: '项目类型',
+            showOverflowTooltip: true,
+            minWidth: 150,
+            align: 'center'
+            // slot: 'type',
+          },
+          {
+            prop: 'code',
+            label: '项目编码',
+            showOverflowTooltip: true,
+            minWidth: 160,
+            slot: 'code',
+            align: 'center'
+          },
+          {
+            prop: 'name',
+            label: '项目名称',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 140
+          },
+
+          {
+            prop: 'responsibleDeptName',
+            label: '负责部门',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 100
+          },
+          {
+            prop: 'responsibleUserName',
+            label: '项目经理',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 100
+          },
+          {
+            prop: 'teamName',
+            label: '项目团队',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 100
+          },
+          {
+            prop: 'cycle',
+            label: '项目周期',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 100
+          },
+          {
+            prop: 'budget',
+            label: '项目预算',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 110,
+            formatter: (_row, _column, cellValue) => {
+              return cellValue
+                ? cellValue +
+                    JSON.parse(
+                      localStorage.getItem('pro_projects_budget_unit')
+                    )[_row.unit].label
+                : '';
+            }
+          },
+          {
+            prop: 'planStartDate',
+            label: '计划开始日期',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 120
+          },
+          {
+            prop: 'planEndDate',
+            label: '计划完成日期',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 120
+          },
+          {
+            prop: 'realStartTime',
+            label: '实际开始日期',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 120
+          },
+          {
+            prop: 'realEndTime',
+            label: '实际完成日期',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 120
+          },
+          {
+            prop: 'cost',
+            label: '费用(元)',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 140
+          },
+          {
+            prop: 'status',
+            label: '项目状态',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 100,
+            slot: 'status'
+          },
+          {
+            prop: 'processStatus',
+            label: '审核状态',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 100,
+            formatter: (_row, _column, cellValue) => {
+              return reviewStatusEnum[_row.processStatus].label;
+            }
+          },
+          {
+            prop: 'isOverTime',
+            label: '是否超时',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 100,
+            slot: 'isOverTime'
+          },
+          {
+            prop: 'isOverbudget',
+            label: '是否超预算',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 100,
+            slot: 'isOverbudget'
+          },
+          {
+            prop: 'speedPercent',
+            label: '项目进度',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 150,
+            slot: 'speedPercent'
+          }
+          // {
+          //   columnKey: 'action',
+          //   label: '操作',
+          //   width: 280,
+          //   align: 'center',
+          //   resizable: false,
+          //   slot: 'action',
+          //   fixed: 'right'
+          // }
+        ],
+        dictList: [],
+        radio: null,
+        current: null,
+        curNodeData: ''
       };
     },
 
     methods: {
+      init() {},
+      onDone(res) {
+        console.log(res);
+      },
       handleClose() {
         this.$emit('update:linkParentDialogFlag', false);
       },
-      selected() {},
-      reload() {},
-      handleNodeClick() {},
-      cellClick() {},
-      datasource() {},
+      selected() {
+        this.$emit('linkParent', this.current);
+        this.handleClose();
+      },
+      reload(where) {
+        this.$refs.table.reload({ page: 1, pageNum: 1, where });
+        this.$refs.table.reRenderTable();
+      },
+      handleNodeClick(data) {
+        this.params.type = data.id;
+        this.reload({ type: data.id });
+      },
+      cellClick(row) {
+        console.log('选择');
+        this.current = row;
+        this.radio = row.id;
+      },
+      async getDictList(code) {
+        let { data: res1 } = await getByCode('pro_projects_status');
+        localStorage.setItem('pro_projects_status', JSON.stringify(init(res1)));
+
+        let { data: res2 } = await getByCode('pro_projects_type');
+        localStorage.setItem('pro_projects_type', JSON.stringify(init(res2)));
+
+        let { data: res3 } = await getByCode('pro_projects_budget_unit');
+        localStorage.setItem(
+          'pro_projects_budget_unit',
+          JSON.stringify(init(res3))
+        );
+
+        // this.dictList[code] = res.map((item) => {
+        //   let values = Object.keys(item);
+        //   return {
+        //     value: values[0],
+        //     label: item[values[0]]
+        //   };
+        // });
+
+        function init(data) {
+          return data.map((item) => {
+            let values = Object.keys(item);
+            return {
+              value: values[0],
+              label: item[values[0]]
+            };
+          });
+        }
+      },
+      /* 表格数据源 */
+      async datasource({ page, limit, where, order }) {
+        if (!this.rootId) {
+          await this.getTreeList();
+          console.log();
+
+          this.$nextTick(() => {
+            this.$refs.treeListRef.$refs.tree.setCurrentKey(this.parentId);
+          });
+
+          // this.$refs.treeListRef.setCurrentKey(this.parentId)
+        }
+        console.log(this.rootId);
+
+        return projectsPageAPI({
+          pageNum: page,
+          size: limit,
+          ...this.params,
+          ...where
+        });
+        return this.tableDataApi({
+          // pageNum: page,
+          // size: limit,
+          // parentId: parent?.id ?? '0',
+          // // parentId:this.parentId,
+          ...this.params
+          // type: this.treeId
+        });
+      },
       async getTreeList() {
         const res = await this.treeApi(this.treeApiCode);
-        console.log(res);
         this.treeList = res;
+        this.rootId = res[0].id;
+        this.params = { ...this.tableDataParams, type: this.rootId };
       }
     },
 
     created() {
-      this.getTreeList();
+      // this.getTreeList();
+      this.getDictList();
+      console.log(this.parentId);
+
+      // this.datasource();
     },
+
     mounted() {}
   };
 </script>

+ 2 - 0
src/utils/request.js

@@ -76,6 +76,8 @@ service.interceptors.response.use(
         });
       }
       return Promise.reject(new Error(error.response.data?.message));
+    } else if (!error?.response?.status) {
+      Message.error('服务调用失败,请联系管理员!');
     }
     return Promise.reject(error);
   }

+ 6 - 7
src/views/BOMmanage/ProjectDetailDialog.vue

@@ -27,10 +27,10 @@
         <el-card class="box-card">
           <div style="width: 100%">
             <el-row style="font-size: 16px">
-              <el-col :span="3" style="color: #1890ff"
+              <el-col :span="5" style="color: #1890ff"
                 >项目名称:{{ rowData.name }}
               </el-col>
-              <el-col :span="3"
+              <el-col :span="5"
                 >项目预算:{{
                   rowData.budget
                     ? rowData.budget +
@@ -38,13 +38,12 @@
                     : ''
                 }}
               </el-col>
-              <el-col :span="3"
+              <el-col :span="5"
                 >项目经理:{{ rowData.responsibleUserName }}
               </el-col>
-              <el-col :span="3">项目周期:{{ rowData.cycle }} </el-col>
-              <el-col :span="3"
-                >项目状态:
-                {{ getDictV('pro_projects_status', rowData.status) }}</el-col
+              <el-col :span="5">项目周期:{{ rowData.cycle }} </el-col>
+              <el-col :span="4"
+                >项目状态:{{ getDictV('pro_projects_status', rowData.status) }}</el-col
               >
             </el-row>
           </div>

+ 201 - 9
src/views/project-manage/project-initiation/components/project-form.vue

@@ -63,12 +63,13 @@
         <el-col :span="8">
           <el-form-item label="从属项目">
             <el-select
+              :disabled="dialogType == 'view'"
               ref="selectRef"
               v-model="form.parentId"
               placeholder="请选择"
               clearable
               @focus.prevent="openLinkParent('f')"
-              @visible-change="openLinkParent('v')"
+              @clear="clearParentId"
             >
               <el-option
                 :key="form.parentId"
@@ -131,7 +132,7 @@
         <el-col :span="8">
           <el-form-item label="项目预算" prop="budget">
             <el-row>
-              <el-col :span="18">
+              <el-col :span="16">
                 <el-input
                   type="number"
                   :min="0"
@@ -140,7 +141,7 @@
                 >
                 </el-input>
               </el-col>
-              <el-col :span="6">
+              <el-col :span="8">
                 <dict-selection
                   dict-name="预算单位"
                   v-model="form.unit"
@@ -336,15 +337,17 @@
 
     <!-- 从属项目打开弹窗 -->
     <linkParentDialog
-      :linkParentDialogFlag.sync="linkParentDialogFlag"
-      :multiple="true"
-      ref="linkParentDialogRef"
       v-if="linkParentDialogFlag"
+      ref="linkParentDialogRef"
+      :linkParentDialogFlag.sync="linkParentDialogFlag"
+      :parentId="form.parentId"
       @linkParent="linkParentFn"
       @close="close"
       :treeApi="getProduceTreeByCode"
       :treeApiCode="'XM1'"
-      tableDataApi="projectsPageAPI"
+      :tableDataApi="projectsPageAPI"
+      :tableDataParams="tableDataParams"
+      :columns="tableColumns"
     ></linkParentDialog>
   </div>
 </template>
@@ -371,6 +374,8 @@
   import { cityData } from 'ele-admin/packages/utils/regions';
 
   import { contactDetail } from '@/api/eos';
+
+  import { reviewStatusEnum } from '@/enum/dict';
   export default {
     name: 'project-form',
     components: {
@@ -438,7 +443,178 @@
     },
     data() {
       return {
-        projectsPageAPI:'',
+        tableDataParams: {
+          code: '',
+          name: ''
+        },
+        tableColumns: [
+          {
+            width: 45,
+            type: 'selection',
+            columnKey: 'selection',
+            align: 'center'
+          },
+          {
+            columnKey: 'index',
+            label: '序号',
+            type: 'index',
+            width: 55,
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'typeName',
+            label: '项目类型',
+            showOverflowTooltip: true,
+            minWidth: 150,
+            align: 'center'
+            // slot: 'type',
+          },
+          {
+            prop: 'code',
+            label: '项目编码',
+            showOverflowTooltip: true,
+            minWidth: 160,
+            slot: 'code',
+            align: 'center'
+          },
+          {
+            prop: 'name',
+            label: '项目名称',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 140
+          },
+
+          {
+            prop: 'responsibleDeptName',
+            label: '负责部门',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 100
+          },
+          {
+            prop: 'responsibleUserName',
+            label: '项目经理',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 100
+          },
+          {
+            prop: 'teamName',
+            label: '项目团队',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 100
+          },
+          {
+            prop: 'cycle',
+            label: '项目周期',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 100
+          },
+          {
+            prop: 'budget',
+            label: '项目预算',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 110,
+            formatter: (_row, _column, cellValue) => {
+              return cellValue
+                ? cellValue +
+                    this.getDictV('pro_projects_budget_unit', _row.unit)
+                : '';
+            }
+          },
+          {
+            prop: 'planStartDate',
+            label: '计划开始日期',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 120
+          },
+          {
+            prop: 'planEndDate',
+            label: '计划完成日期',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 120
+          },
+          {
+            prop: 'realStartTime',
+            label: '实际开始日期',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 120
+          },
+          {
+            prop: 'realEndTime',
+            label: '实际完成日期',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 120
+          },
+          {
+            prop: 'cost',
+            label: '费用(元)',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 140
+          },
+          {
+            prop: 'status',
+            label: '项目状态',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 100,
+            slot: 'status'
+          },
+          {
+            prop: 'processStatus',
+            label: '审核状态',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 100,
+            formatter: (_row, _column, cellValue) => {
+              return reviewStatusEnum[_row.processStatus].label;
+            }
+          },
+          {
+            prop: 'isOverTime',
+            label: '是否超时',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 100,
+            slot: 'isOverTime'
+          },
+          {
+            prop: 'isOverbudget',
+            label: '是否超预算',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 100,
+            slot: 'isOverbudget'
+          },
+          {
+            prop: 'speedPercent',
+            label: '项目进度',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 150,
+            slot: 'speedPercent'
+          },
+          {
+            columnKey: 'action',
+            label: '操作',
+            width: 280,
+            align: 'center',
+            resizable: false,
+            slot: 'action',
+            fixed: 'right'
+          }
+        ],
+
         getProduceTreeByCode: '',
         linkParentDialogFlag: false,
         rootId: [],
@@ -450,6 +626,10 @@
             value: 1,
             label: '订单'
           },
+          {
+            value: 2,
+            label: '客户'
+          },
           {
             value: 3,
             label: '合同'
@@ -547,6 +727,7 @@
       };
     },
     async created() {
+      //  this.projectsPageAPI = projectsPageAPI;
       this.projectList = await projectsToTreeAPI({
         processStatus: '2',
         treeType: '0'
@@ -563,6 +744,12 @@
     },
 
     methods: {
+      clearParentId() {
+        this.form.parentId = null;
+        this.form.parentName = null;
+        console.log('qing');
+      },
+      projectsPageAPI,
       close() {
         this.linkParentDialogFlag = false;
       },
@@ -572,7 +759,12 @@
         _this.$refs.selectRef.blur();
         this.linkParentDialogFlag = true;
       },
-      linkParentFn() {},
+      linkParentFn(obj) {
+        console.log(obj);
+
+        this.form.parentId = obj.id;
+        this.form.parentName = obj.name;
+      },
       setCycleValue(val, prop) {
         if (!this.form[prop] || !val) return (this.form.cycle = '');
         const a = moment(this.form.planEndDate);

+ 0 - 2
src/views/project-manage/project-initiation/index.vue

@@ -581,8 +581,6 @@
       },
       /* 表格数据源 */
       async datasource({ page, limit, where, parent }) {
-        console.log(parent);
-        
         await this.getDictList('pro_projects_status');
         await this.getDictList('pro_projects_type');
         await this.getDictList('pro_projects_budget_unit');

+ 3 - 1
vue.config.js

@@ -12,6 +12,7 @@ module.exports = {
   lintOnSave: false,
   productionSourceMap: false,
   configureWebpack: {
+    devtool: 'source-map',
     performance: {
       maxAssetSize: 2000000,
       maxEntrypointSize: 2000000
@@ -31,9 +32,10 @@ module.exports = {
     proxy: {
       // 当我们的本地的请求 有/api的时候,就会代理我们的请求地址向另外一个服务器发出请求
       '/api': {
-        target: 'http://192.168.1.125:18086',
+        // target: 'http://192.168.1.125:18086',
         // target: 'http://192.168.1.251:18086',
         // target: 'http://192.168.1.176:18086',
+        target: 'http://192.168.1.158:18086',
 
         changeOrigin: true, // 只有这个值为true的情况下 才表示开启跨域
         pathRewrite: {