Explorar el Código

场站信息页面

yuanhao hace 2 años
padre
commit
f4a197b209

+ 1 - 1
in-cloud-ui/.eslintrc.js

@@ -26,7 +26,7 @@ module.exports = {
         '**/tests/unit/**/*.spec.{j,t}s?(x)',
       ],
       env: {
-        jest: true,
+        jest: false,
       },
     },
   ],

+ 48 - 0
in-cloud-ui/src/api/integrationCompany.js

@@ -0,0 +1,48 @@
+import request from '@/utils/request'
+
+export function fetchList(query) {
+  return request({
+    url: '/integrationCompany/page',
+    method: 'get',
+    params: query
+  })
+}
+
+export function addObj(obj) {
+  return request({
+    url: '/integrationCompany',
+    method: 'post',
+    data: obj
+  })
+}
+
+export function getObj(code) {
+  return request({
+    url: '/integrationCompany/' + code,
+    method: 'get'
+  })
+}
+
+
+export function getAll() {
+  return request({
+    url: '/integrationCompany/all',
+    method: 'get'
+  })
+}
+
+export function delObj(id) {
+  return request({
+    url: '/integrationCompany/' + id,
+    method: 'delete'
+  })
+}
+
+export function putObj(obj) {
+  return request({
+    url: '/integrationCompany',
+    method: 'put',
+    data: obj
+  })
+
+}

+ 49 - 0
in-cloud-ui/src/api/station.js

@@ -0,0 +1,49 @@
+import request from '@/utils/request'
+
+export function fetchList(query) {
+  return request({
+    url: '/station/page',
+    method: 'get',
+    params: query
+  })
+}
+
+export function addObj(obj) {
+  return request({
+    url: '/station',
+    method: 'post',
+    data: obj
+  })
+}
+
+export function getObj(code) {
+  return request({
+    url: '/station/' + code,
+    method: 'get'
+  })
+}
+
+
+export function getAll() {
+  return request({
+    url: '/station/all',
+    method: 'get'
+  })
+}
+
+
+export function delObj(id) {
+  return request({
+    url: '/station/' + id,
+    method: 'delete'
+  })
+}
+
+export function putObj(obj) {
+  return request({
+    url: '/station',
+    method: 'put',
+    data: obj
+  })
+
+}

+ 0 - 1
in-cloud-ui/src/utils/request.js

@@ -53,7 +53,6 @@ const instance = axios.create({
 instance.interceptors.request.use(
   (config) => {
     if (store.getters['user/accessToken']) {
-      alert(store.getters['user/accessToken'])
       config.headers[tokenName] = store.getters['user/accessToken']
     }
     //这里会过滤所有为空、0、false的key,如果不需要请自行注释

+ 2 - 2
in-cloud-ui/src/views/index/components/VersionInformation.vue

@@ -42,14 +42,14 @@
                 Plus付费版本 购买源码 ¥799
               </el-button>
             </a>
-            <a
+            <!--            <a
               href="https://github.com/chuzhixin/vue-admin-beautiful/"
               target="_blank"
             >
               <el-button style="margin-left: 10px" type="warning">
                 开源免费版
               </el-button>
-            </a>
+            </a>-->
           </td>
         </tr>
       </table>

+ 75 - 0
in-cloud-ui/src/views/vab/table/components/TableEdit.vue

@@ -0,0 +1,75 @@
+<template>
+  <el-dialog
+    :title="title"
+    :visible.sync="dialogFormVisible"
+    width="500px"
+    @close="close"
+  >
+    <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+      <el-form-item label="标题" prop="title">
+        <el-input v-model.trim="form.title" autocomplete="off"></el-input>
+      </el-form-item>
+      <el-form-item label="作者" prop="author">
+        <el-input v-model.trim="form.author" autocomplete="off"></el-input>
+      </el-form-item>
+    </el-form>
+    <div slot="footer" class="dialog-footer">
+      <el-button @click="close">取 消</el-button>
+      <el-button type="primary" @click="save">确 定</el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+  import { doEdit } from '@/api/table'
+
+  export default {
+    name: 'TableEdit',
+    data() {
+      return {
+        form: {
+          title: '',
+          author: '',
+        },
+        rules: {
+          title: [{ required: true, trigger: 'blur', message: '请输入标题' }],
+          author: [{ required: true, trigger: 'blur', message: '请输入作者' }],
+        },
+        title: '',
+        dialogFormVisible: false,
+      }
+    },
+    created() {},
+    methods: {
+      showEdit(row) {
+        if (!row) {
+          this.title = '添加'
+        } else {
+          this.title = '编辑'
+          this.form = Object.assign({}, row)
+        }
+        this.dialogFormVisible = true
+      },
+      close() {
+        this.$refs['form'].resetFields()
+        this.form = this.$options.data().form
+        this.dialogFormVisible = false
+        this.$emit('fetch-data')
+      },
+      save() {
+        this.$refs['form'].validate(async (valid) => {
+          if (valid) {
+            const { msg } = await doEdit(this.form)
+            this.$baseMessage(msg, 'success')
+            this.$refs['form'].resetFields()
+            this.dialogFormVisible = false
+            this.$emit('fetch-data')
+            this.form = this.$options.data().form
+          } else {
+            return false
+          }
+        })
+      },
+    },
+  }
+</script>

+ 307 - 9
in-cloud-ui/src/views/vab/table/index.vue

@@ -1,26 +1,324 @@
 <template>
-  <div class="table-container"></div>
+  <div class="table-container">
+    <vab-query-form>
+      <vab-query-form-left-panel>
+        <el-form
+          ref="searchForm"
+          :model="searchForm"
+          :inline="true"
+          @submit.native.prevent
+        >
+          <el-form-item>
+            <el-input v-model="searchForm.stationCode" placeholder="场站标识" />
+          </el-form-item>
+          <el-form-item>
+            <el-button
+              icon="el-icon-search"
+              type="primary"
+              native-type="submit"
+              @click="handleQuery"
+            >
+              查询
+            </el-button>
+            <el-button icon="el-icon-plus" type="primary" @click="handleAdd">
+              添加
+            </el-button>
+          </el-form-item>
+        </el-form>
+      </vab-query-form-left-panel>
+    </vab-query-form>
+
+    <el-table
+      ref="tableSort"
+      v-loading="listLoading"
+      :data="tableData"
+      :element-loading-text="elementLoadingText"
+      :height="height"
+    >
+      <el-table-column show-overflow-tooltip label="序号" width="95">
+        <template #default="scope">
+          {{ scope.$index + 1 }}
+        </template>
+      </el-table-column>
+      <el-table-column show-overflow-tooltip prop="name" label="场站名称" />
+      <el-table-column
+        show-overflow-tooltip
+        label="场站编码"
+        prop="stationCode"
+      />
+      <el-table-column
+        show-overflow-tooltip
+        label="场站标识"
+        prop="signCode"
+      />
+      <el-table-column
+        show-overflow-tooltip
+        label="场站类型"
+        prop="type"
+        :formatter="formatType"
+      />
+      <el-table-column show-overflow-tooltip label="用户名" prop="username" />
+      <el-table-column show-overflow-tooltip label="密码" prop="password" />
+      <el-table-column show-overflow-tooltip label="通讯秘钥" prop="comKey" />
+      <el-table-column
+        show-overflow-tooltip
+        label="秘钥过期时间"
+        prop="keyTime"
+      />
+
+      <el-table-column
+        show-overflow-tooltip
+        label="一体化公司"
+        prop="inCode"
+        :formatter="formatCompany"
+      />
+      <el-table-column show-overflow-tooltip label="状态" prop="state" />
+      <el-table-column show-overflow-tooltip label=" 推送天数" prop="days" />
+
+      <el-table-column show-overflow-tooltip label="操作" width="180px">
+        <template #default="{ row }">
+          <el-button type="text" @click="handleEdit(row)">编辑</el-button>
+          <el-button type="text" @click="handleDelete(row)">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <el-pagination
+      :background="background"
+      :current-page="page.currentPage"
+      :layout="layout"
+      :page-size="page.pageSize"
+      :total="page.total"
+      @current-change="handleCurrentChange"
+      @size-change="handleSizeChange"
+    ></el-pagination>
+
+    <el-dialog
+      :title="title"
+      :visible.sync="dialogFormVisible"
+      width="500px"
+      @close="close"
+    >
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="场站名称" prop="name">
+          <el-input v-model.trim="form.name" autocomplete="off"></el-input>
+        </el-form-item>
+        <el-form-item label="场站编码" prop="stationCode">
+          <el-input v-model.trim="form.stationCode" autocomplete="off"></el-input>
+        </el-form-item>
+        <el-form-item label="场站标识" prop="signCode">
+          <el-input v-model.trim="form.signCode" autocomplete="off"></el-input>
+        </el-form-item>
+        <el-form-item label="场站类型" prop="type">
+          <el-select clearable v-model.trim="form.type" placeholder="请选择">
+            <el-option
+              v-for="item in this.elType"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value">
+            </el-option>
+          </el-select>
+        </el-form-item>
+
+        <el-form-item label="用户名" prop="username">
+          <el-input v-model.trim="form.username" autocomplete="off"></el-input>
+        </el-form-item>
+        <el-form-item label="密码" prop="password">
+          <el-input v-model.trim="form.password" autocomplete="off"></el-input>
+        </el-form-item>
+
+        <el-form-item label="推送天速" prop="days">
+          <el-input v-model.trim="form.days" autocomplete="off"></el-input>
+        </el-form-item>
+
+
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="close">取 消</el-button>
+        <el-button type="primary" @click="save">确 定</el-button>
+      </div>
+    </el-dialog>
+  </div>
 </template>
 
 <script>
-  import { test } from '@/api/test'
+  import { fetchList, addObj, putObj, delObj, getObj } from '@/api/station'
+  import { getAll } from '@/api/integrationCompany'
+
   export default {
     name: 'ComprehensiveTable',
-    components: {},
-    filters: {},
+
+
     data() {
-      return {}
+      return {
+        dialogFormVisible: false,
+        title:'',
+        tableData: [],
+        companys: [],
+        elType: [
+          { label: '光电', value: 'E1' },
+          { label: '风电', value: 'E2' },
+        ],
+        searchForm: {
+          stationCode: null,
+        },
+        form:{
+
+        },
+        imgShow: true,
+        list: [],
+        imageList: [],
+        listLoading: true,
+        layout: 'total, sizes, prev, pager, next, jumper',
+        total: 0,
+        background: true,
+        selectRows: '',
+        elementLoadingText: '正在加载...',
+        page: {
+          total: 0, // 总页数
+          currentPage: 1, // 当前页数
+          pageSize: 20, // 每页显示多少条
+        },
+        rules: {
+          name: [{ required: true, trigger: 'blur', message: '请输入标题' }],
+          type: [{ required: true, trigger: 'blur', message: '请输入作者' }],
+        },
+      }
+    },
+    computed: {
+      height() {
+        return this.$baseTableHeight()
+      },
     },
-    computed: {},
     created() {
-      this.fetchData()
+
+      this.getCompany()
     },
     beforeDestroy() {},
     mounted() {},
     methods: {
+      getCompany() {
+        getAll()
+          .then((response) => {
+            this.companys = response.data
+            this.fetchData()
+            this.listLoading = false
+          })
+          .catch(() => {
+            this.listLoading = false
+          })
+      },
+
+      handleAdd() {
+        this.form = {},
+        this.title ="新增"
+        this.dialogFormVisible = true
+      },
+      handleEdit(row) {
+        this.form = row
+        this.title ="修改"
+        this.dialogFormVisible = true
+      },
+      handleDelete(row) {
+        this.$baseConfirm('你确定要删除当前项吗', null, async () => {
+          const { msg } = await delObj(row.id)
+          this.$baseMessage(msg, 'success')
+          this.fetchData()
+        })
+      },
+      handleSizeChange(val) {
+        this.page.pageSize = val
+        this.page.currentPage = 1
+        this.fetchData()
+      },
+      handleCurrentChange(val) {
+        this.page.currentPage = val
+        this.fetchData()
+      },
+      handleQuery() {
+        for (var v in this.searchForm) {
+          if (this.searchForm[v] == '') {
+            delete this.searchForm[v]
+          }
+        }
+
+        this.page.currentPage = 1
+        this.fetchData()
+      },
       async fetchData() {
-        const { data } = await test()
-        alert(data)
+        this.listLoading = true
+        fetchList(
+          Object.assign(
+            {
+              current: this.page.currentPage,
+              size: this.page.pageSize,
+            },
+            this.searchForm
+          )
+        )
+          .then((response) => {
+            this.tableData = response.data.records
+            this.page.total = response.data.total
+            this.listLoading = false
+          })
+          .catch(() => {
+            this.listLoading = false
+          })
+      },
+      testMessage() {
+        this.$baseMessage('test1', 'success')
+      },
+      testALert() {
+        this.$baseAlert('11')
+        this.$baseAlert('11', '自定义标题', () => {
+          /* 可以写回调; */
+        })
+        this.$baseAlert('11', null, () => {
+          /* 可以写回调; */
+        })
+      },
+
+      testNotify() {
+        this.$baseNotify('测试消息提示', 'test', 'success', 'bottom-right')
+      },
+
+      formatType(row, column) {
+        for (let i = 0; i < this.elType.length; i++) {
+          if (row.type == this.elType[i].value) {
+            return this.elType[i].label
+          }
+        }
+      },
+
+      formatCompany(row, column) {
+        for (let i = 0; i < this.companys.length; i++) {
+          if (row.inCode == this.companys[i].code) {
+            return this.companys[i].name
+          }
+        }
+      },
+
+
+      close() {
+        this.$refs['form'].resetFields()
+        this.form = this.$options.data().form
+        this.dialogFormVisible = false
+        this.$emit('fetch-data')
+      },
+      save() {
+        this.$refs.form.validate((valid)=>{
+          if (valid){
+            this.listLoading = true
+            addObj(this.form).then(response => {
+              this.dialogFormVisible = false
+              this.fetchData()
+              this.listLoading = false
+            }).catch(() => {
+              this.listLoading = false
+            })
+          }else{
+            return false;
+          }
+        })
       },
     },
   }

+ 2 - 2
in-cloud-ui/vue.config.js

@@ -52,8 +52,8 @@ module.exports = {
     open: true,
     noInfo: false,
     overlay: {
-      warnings: true,
-      errors: true,
+      warnings: false,
+      errors: false,
     },
     //after: mockServer(),
     proxy: {

+ 17 - 0
in-cloud/src/main/java/com/jiayue/insu/incloud/config/MyBatisPlusConfig.java

@@ -0,0 +1,17 @@
+package com.jiayue.insu.incloud.config;
+
+import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class MyBatisPlusConfig {
+
+    @Bean
+    public MybatisPlusInterceptor mybatisPlusInterceptor() {
+        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
+        interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
+        return interceptor;
+    }
+}

+ 91 - 0
in-cloud/src/main/java/com/jiayue/insu/incloud/controller/IntegrationCompanyController.java

@@ -0,0 +1,91 @@
+package com.jiayue.insu.incloud.controller;
+
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.jiayue.insu.common.core.util.R;
+import com.jiayue.insu.incloud.entity.IntegrationCompany;
+import com.jiayue.insu.incloud.service.IntegrationCompanyService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+
+
+/**
+ * IntegrationCompanyController
+ *
+ * @author yh
+ * @date 2022-03-18 15:48:48
+ */
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/integrationCompany")
+public class IntegrationCompanyController {
+
+    private final IntegrationCompanyService integrationCompanyService;
+
+    /**
+     * 分页查询
+     *
+     * @param page   分页对象
+     * @param integrationCompany station
+     * @return
+     */
+
+    @GetMapping("/page")
+    public R getStationPage(Page page, IntegrationCompany integrationCompany) {
+        return R.ok(integrationCompanyService.page(page, Wrappers.query(integrationCompany)));
+    }
+
+    @GetMapping("/all")
+    public R getAll() {
+        return R.ok(integrationCompanyService.list());
+    }
+
+    /**
+     * 通过code查询场站信息
+     *
+     * @param code code
+     * @return R
+     */
+    @GetMapping("/{code}")
+    public R getByCode(@PathVariable("code") String  code) {
+        return R.ok(integrationCompanyService.findByCode(code));
+    }
+
+
+    /**
+     * 新增integrationCompany
+     *
+     * @param integrationCompany station
+     * @return R
+     */
+
+    @PostMapping
+    public R save(@RequestBody IntegrationCompany integrationCompany) {
+        return R.ok(integrationCompanyService.save(integrationCompany));
+    }
+
+    /**
+     * 修改integrationCompany
+     *
+     * @param integrationCompany station
+     * @return R
+     */
+
+    @PutMapping
+    public R updateById(@RequestBody IntegrationCompany integrationCompany) {
+        return R.ok(integrationCompanyService.updateById(integrationCompany));
+    }
+
+    /**
+     * 通过id删除
+     *
+     * @param id id
+     * @return R
+     */
+    @DeleteMapping("/{id}")
+    public R removeById(@PathVariable Long id) {
+        return R.ok(integrationCompanyService.removeById(id));
+    }
+
+
+}

+ 91 - 0
in-cloud/src/main/java/com/jiayue/insu/incloud/controller/StationController.java

@@ -0,0 +1,91 @@
+package com.jiayue.insu.incloud.controller;
+
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.jiayue.insu.common.core.util.R;
+import com.jiayue.insu.incloud.entity.Station;
+import com.jiayue.insu.incloud.service.StationService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+
+
+/**
+ * StationController
+ *
+ * @author yh
+ * @date 2022-03-18 15:48:48
+ */
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/station")
+public class StationController {
+
+    private final StationService stationService;
+
+    /**
+     * 分页查询
+     *
+     * @param page   分页对象
+     * @param station station
+     * @return
+     */
+
+    @GetMapping("/page")
+    public R getStationPage(Page page, Station station) {
+        return R.ok(stationService.page(page, Wrappers.query(station)));
+    }
+
+    @GetMapping("/all")
+    public R getAll() {
+        return R.ok(stationService.list());
+    }
+
+    /**
+     * 通过code查询场站信息
+     *
+     * @param code code
+     * @return R
+     */
+    @GetMapping("/{code}")
+    public R getByCode(@PathVariable("code") String  code) {
+        return R.ok(stationService.findByStationCode(code));
+    }
+
+
+    /**
+     * 新增station
+     *
+     * @param station station
+     * @return R
+     */
+
+    @PostMapping
+    public R save(@RequestBody Station station) {
+        return R.ok(stationService.save(station));
+    }
+
+    /**
+     * 修改equipmentAttribute
+     *
+     * @param station station
+     * @return R
+     */
+
+    @PutMapping
+    public R updateById(@RequestBody Station station) {
+        return R.ok(stationService.updateById(station));
+    }
+
+    /**
+     * 通过id删除
+     *
+     * @param id id
+     * @return R
+     */
+    @DeleteMapping("/{id}")
+    public R removeById(@PathVariable Long id) {
+        return R.ok(stationService.removeById(id));
+    }
+
+
+}

+ 2 - 0
in-cloud/src/main/java/com/jiayue/insu/incloud/entity/Station.java

@@ -65,6 +65,8 @@ public class Station extends BaseEntity {
      */
     LocalDateTime keyTime;
 
+    Integer days;
+
 
 
 

+ 8 - 6
in-cloud/src/main/java/com/jiayue/insu/incloud/pulldata/PullCorrectDataForQNHL.java

@@ -69,16 +69,16 @@ public class PullCorrectDataForQNHL implements IPullInitCorrectData{
     @Value("${minio.fileurl}")
     String fileurl;
 
-    @Value("${minlo.logurl}")
+    @Value("${minio.logurl}")
     private String logurl;
 
-    @Value("${minlo.host}")
+    @Value("${minio.host}")
     private String minloHost;
 
-    @Value("${minlo.user}")
+    @Value("${minio.user}")
     private String minloUser;
 
-    @Value("${minlo.pwd}")
+    @Value("${minio.pwd}")
     private String minloPwd;
 
     @Override
@@ -144,7 +144,7 @@ public class PullCorrectDataForQNHL implements IPullInitCorrectData{
 
                             List<ForecastData> aList = new ArrayList<>();
                             long startTime = DateUtil.beginOfDay(new Date()).getTime();
-                            long endTime = DateUtil.offsetDay(new Date(startTime), 10).getTime();
+                            long endTime = DateUtil.offsetDay(new Date(startTime), st.getDays()).getTime();
                             aList = forecastDataService.findTimeByStation(station.getStationCode(), startTime, endTime);
                             log.info(station.getStationCode() + " 请求短期修正数据返回内容:{}", response);
 
@@ -161,7 +161,9 @@ public class PullCorrectDataForQNHL implements IPullInitCorrectData{
                                     }
 
                                     /**************检测解析数据完整性*******************/
-                                    if (list.size() < 961) {
+                                    BigDecimal one = new BigDecimal("1");
+                                    BigDecimal checkCount = new BigDecimal( st.getDays().toString()).add(one).multiply(new BigDecimal("96")).add(one);
+                                    if (list.size() < checkCount.intValue()) {
                                         record.setState(StatusEnum.DATA_DEFICIENCY.getCode());
                                         record.setStateContent(StatusEnum.DATA_DEFICIENCY.getMsg());
                                         log.warn( "========== {}:{} ==> 请求短期修正数据缺数: {}" ,integrationCompany.getName(),st.getStationCode(),list.size());

+ 5 - 3
in-cloud/src/main/java/com/jiayue/insu/incloud/pushdata/PushDataForQNHL.java

@@ -28,6 +28,7 @@ import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
+import java.math.BigDecimal;
 import java.time.LocalDateTime;
 import java.util.*;
 import java.util.stream.Collectors;
@@ -88,7 +89,7 @@ public class PushDataForQNHL implements IPushInitForecastData {
 
         if (StrUtil.isNotEmpty(token) &&  LocalDateTime.now().isBefore(tokenTime)) {
             long startTime = DateUtil.beginOfDay(new Date()).getTime();
-            long endTime = DateUtil.offsetDay(new Date(startTime), 10).getTime();
+            long endTime = DateUtil.offsetDay(new Date(startTime), st.getDays()).getTime();
             long momentTime = 900000L;
             List<ForecastData> aList;
             aList = forecastDataService.findTimeByStation(station.getStationCode(), startTime, endTime);
@@ -115,9 +116,10 @@ public class PushDataForQNHL implements IPushInitForecastData {
                 }
                 /**************************补点 end*************************/
 
-
+                BigDecimal one = new BigDecimal("1");
+                BigDecimal checkCount = new BigDecimal( st.getDays().toString()).add(one).multiply(new BigDecimal("96")).add(one);
                 //如果数据小于961条 不上送数据
-                if (aList.size() >= 961) {
+                if (aList.size() >= checkCount.intValue()) {
 
                     if (CommonStant.ET_PHOTOVOLTAIC.equals(station.getType())) {
                         requestVo = generatePhotovoltaicRequest(station.getSignCode(), aList, startTime, endTime);

+ 1 - 1
in-cloud/src/main/resources/bootstrap.yml

@@ -46,7 +46,7 @@ spring:
 
 
 
-minlo:
+minio:
   pull:
     url: https://117.78.19.70:9010/client/getFileLogsForAio/
     fileurl: https://117.78.19.70:9010/client/getFileById?id=