From 7482cae8ba1c8a2c57c09fef751838fb76891424 Mon Sep 17 00:00:00 2001
From: zhaowei <zhaowei>
Date: 星期一, 05 八月 2024 15:14:46 +0800
Subject: [PATCH] 新增大屏车间管理页面

---
 src/views/system/WorkshopSignageManagement.vue |  535 ++++++++++++++++++++++++++++++++++++++++++++
 src/views/system/modules/WorkshopModal.vue     |  144 ++++++++++++
 2 files changed, 679 insertions(+), 0 deletions(-)

diff --git a/src/views/system/WorkshopSignageManagement.vue b/src/views/system/WorkshopSignageManagement.vue
new file mode 100644
index 0000000..1c02197
--- /dev/null
+++ b/src/views/system/WorkshopSignageManagement.vue
@@ -0,0 +1,535 @@
+<template>
+  <a-row :gutter="10">
+    <a-col :md="leftColMd" :sm="24" style="margin-bottom: 20px">
+      <a-card :bordered="false">
+        <!-- 鏌ヨ鍖哄煙 -->
+        <div class="table-page-search-wrapper">
+          <!-- 鎼滅储鍖哄煙 -->
+          <a-form layout="inline" @keyup.enter.native="searchQuery">
+            <a-row :gutter="24">
+              <a-col :md="8" :sm="8">
+                <a-form-item label="杞﹂棿鍚嶇О" :labelCol="{ span: 5 }" :wrapperCol="{ span: 19}">
+                  <a-input placeholder="" v-model="queryParam.workshopName"></a-input>
+                </a-form-item>
+              </a-col>
+              <span style="float: left; overflow: hidden" class="table-page-search-submitButtons">
+                <a-col>
+                  <a-space>
+                    <a-button type="primary" @click="searchQuery" icon="search">鏌ヨ</a-button>
+                    <a-button type="primary" @click="searchReset" icon="reload">閲嶇疆</a-button>
+                  </a-space>
+                </a-col>
+              </span>
+            </a-row>
+          </a-form>
+        </div>
+        <!-- 鎿嶄綔鎸夐挳鍖哄煙 -->
+        <div class="table-operator" style="margin: 5px 0 10px 2px">
+          <a-button @click="handleAdd" type="primary" icon="plus">鏂板缓杞﹂棿</a-button>
+        </div>
+
+        <div class="ant-alert ant-alert-info" style="margin-bottom: 16px">
+          <i class="anticon anticon-info-circle ant-alert-icon"> </i> 宸查�夋嫨
+          <a
+            ><b>{{ selectedRowKeys1.length }}</b></a
+          >椤�
+          <a style="margin-left: 24px" @click="onClearSelected1">娓呯┖</a>
+        </div>
+
+        <div style="margin-top: 15px">
+          <a-table
+            style="height: 500px"
+            ref="table"
+            size="middle"
+            bordered
+            rowKey="id"
+            :columns="columns"
+            :dataSource="dataSource"
+            :pagination="ipagination"
+            :loading="loading"
+            :rowSelection="{ selectedRowKeys: selectedRowKeys1, onChange: onSelectChange1, type: 'radio' }"
+            @change="handleTableChange"
+          >
+            <template slot="backgroundImage" slot-scope="text, record">
+              <img :src="getImgView(record.backgroundImage)" width="50" height="50" />
+            </template>
+            <span slot="action" slot-scope="text, record">
+              <a @click="handleOpen(record)">璁惧</a>
+              <a-divider type="vertical" />
+              <a-dropdown>
+                <a class="ant-dropdown-link"> 鏇村 <a-icon type="down" /> </a>
+                <a-menu slot="overlay">
+                  <a-menu-item>
+                    <a @click="handleEdit(record)">缂栬緫</a>
+                  </a-menu-item>
+                  <a-menu-item>
+                    <a-popconfirm title="纭畾鍒犻櫎鍚�?" @confirm="() => handleDelete1(record.id)">
+                      <a>鍒犻櫎</a>
+                    </a-popconfirm>
+                  </a-menu-item>
+                </a-menu>
+              </a-dropdown>
+            </span>
+          </a-table>
+        </div>
+      </a-card>
+    </a-col>
+    <a-col :md="rightColMd" :sm="24" v-if="this.rightcolval == 1">
+      <a-card :bordered="false">
+        <div @click="hideUserList" class="close-circle">
+          <a-icon type="close-circle"/>
+        </div>
+        <!-- 鏌ヨ鍖哄煙 -->
+        <div class="table-page-search-wrapper">
+          <a-form layout="inline">
+            <a-row :gutter="24">
+              <a-col :md="12" :sm="12">
+                <a-form-item label="缁熶竴缂栫爜">
+                  <a-input placeholder="" v-model="queryParam2.equipmentId"></a-input>
+                </a-form-item>
+              </a-col>
+              <span style="float: left; overflow: hidden" class="table-page-search-submitButtons">
+                <a-col :md="9" :sm="24">
+                  <a-button type="primary" @click="searchQuery2" icon="search" style="margin-left: 21px">鏌ヨ</a-button>
+                  <a-button type="primary" @click="searchReset2" icon="reload" style="margin-left: 8px">閲嶇疆</a-button>
+                </a-col>
+              </span>
+            </a-row>
+          </a-form>
+        </div>
+        <!-- 鎿嶄綔鎸夐挳鍖哄煙 -->
+        <div class="table-operator" :md="24" :sm="24">
+          <a-button @click="handleAddDeviceInWorkshop" type="primary" icon="plus"  style="margin: 5px 0 10px 2px"
+            >宸叉湁璁惧
+          </a-button>
+
+          <a-dropdown v-if="selectedRowKeys2.length > 0">
+            <a-menu slot="overlay">
+              <a-menu-item key="1" @click="batchDel2">
+                <a-icon type="delete" />
+                鍒犻櫎
+              </a-menu-item>
+            </a-menu>
+            <a-button style="margin-left: 8px">
+              鎵归噺鎿嶄綔
+              <a-icon type="down" />
+            </a-button>
+          </a-dropdown>
+        </div>
+
+        <!-- table鍖哄煙-begin -->
+        <div>
+          <div class="ant-alert ant-alert-info" style="margin-bottom: 16px">
+            <i class="anticon anticon-info-circle ant-alert-icon"></i> 宸查�夋嫨
+            <a style="font-weight: 600">{{ selectedRowKeys2.length }}</a
+            >椤�
+            <a style="margin-left: 24px" @click="onClearSelected2">娓呯┖</a>
+          </div>
+          <a-table
+            style="height: 500px"
+            ref="table2"
+            bordered
+            size="middle"
+            rowKey="equipmentId"
+            :columns="columns2"
+            :dataSource="dataSource2"
+            :pagination="ipagination2"
+            :loading="loading2"
+            :rowSelection="{ selectedRowKeys: selectedRowKeys2, onChange: onSelectChange2 }"
+            @change="handleTableChange2"
+          >
+            <span slot="action" slot-scope="text, record">
+              <a-popconfirm title="纭畾鍒犻櫎鍚�?" @confirm="() => handleDelete2(record.equipmentId)">
+                <a>鍒犻櫎</a>
+              </a-popconfirm>
+            </span>
+          </a-table>
+        </div>
+      </a-card>
+    </a-col>
+    <!-- 琛ㄥ崟鍖哄煙 -->
+    <workshop-modal ref="modalForm" @ok="modalFormOk"></workshop-modal>
+    <!--鏂板杞﹂棿-->
+    <select-device-drawer ref="selectDeviceDrawer" @selectFinished="selectOK" :title="'娣诲姞宸叉湁璁惧'"></select-device-drawer>
+    <!--宸叉湁璁惧-->
+  </a-row>
+</template>
+<script>
+import { JeecgListMixin } from '@/mixins/JeecgListMixin'
+import { deleteAction, postAction, getAction } from '@/api/manage'
+import SelectDeviceDrawer from './modules/SelectDeviceDrawer'
+import WorkshopModal from './modules/WorkshopModal'
+import { filterObj } from '@/utils/util'
+import moment from 'moment'
+
+export default {
+  name: 'WorkshopSignageManagement',
+  mixins: [JeecgListMixin],
+  components: {
+    SelectDeviceDrawer,
+    WorkshopModal,
+    moment,
+  },
+  data() {
+    return {
+      model1: {},
+      model2: {},
+      currentRoleId: '',
+      currentWorkshopId: '',
+      queryParam1: {},
+      queryParam2: {},
+      dataSource1: [],
+      dataSource2: [],
+      ipagination1: {
+        current: 1,
+        pageSize: 10,
+        pageSizeOptions: ['10', '20', '30'],
+        showTotal: (total, range) => {
+          return range[0] + '-' + range[1] + ' 鍏�' + total + '鏉�'
+        },
+        showQuickJumper: true,
+        showSizeChanger: true,
+        total: 0,
+      },
+      ipagination2: {
+        current: 1,
+        pageSize: 10,
+        pageSizeOptions: ['10', '20', '30'],
+        showTotal: (total, range) => {
+          return range[0] + '-' + range[1] + ' 鍏�' + total + '鏉�'
+        },
+        showQuickJumper: true,
+        showSizeChanger: true,
+        total: 0,
+      },
+      isorter1: {
+        column: 'createTime',
+        order: 'desc',
+      },
+      isorter2: {
+        column: 'createTime',
+        order: 'desc',
+      },
+      filters1: {},
+      filters2: {},
+      loading1: false,
+      loading2: false,
+      selectedRowKeys1: [],
+      selectedRowKeys2: [],
+      selectionRows1: [],
+      selectionRows2: [],
+      test: {},
+      rightcolval: 0,
+      columns: [
+        {
+          title: '杞﹂棿鍚嶇О',
+          align: 'center',
+          dataIndex: 'workshopName',
+        },
+        {
+          title: '杞﹂棿鑳屾櫙鍥�',
+          dataIndex: 'backgroundImage',
+          align: 'center',
+          scopedSlots: { customRender: 'backgroundImage' },
+        },
+        {
+          title: '璁惧缂栧彿棰滆壊',
+          dataIndex: 'equipmentIdColor',
+          align: 'center',
+        },
+        {
+          title: '鎿嶄綔',
+          dataIndex: 'action',
+          align: 'center',
+          scopedSlots: { customRender: 'action' },
+        },
+      ],
+      columns2: [
+        {
+          title: '缁熶竴缂栫爜',
+          align: 'center',
+          dataIndex: 'equipmentId',
+          width: 120,
+        },
+        {
+          title: '璁惧鍚嶇О',
+          align: 'center',
+          width: 100,
+          dataIndex: 'equipmentName',
+        },
+        {
+          title: '璁惧绫诲瀷',
+          align: 'center',
+          width: 80,
+          dataIndex: 'equipmentType',
+        },
+
+        {
+          title: '鎿嶄綔',
+          dataIndex: 'action',
+          scopedSlots: { customRender: 'action' },
+          align: 'center',
+          width: 120,
+        },
+      ],
+      // 楂樼骇鏌ヨ鍙傛暟
+      superQueryParams2: '',
+      // 楂樼骇鏌ヨ鎷兼帴鏉′欢
+      superQueryMatchType2: 'and',
+      url: {
+        list: '/mdc/mdcWorkshopInfo/list',
+        delete: '/mdc/mdcWorkshopInfo/delete',
+        list2: '/mdc/mdcWorkshopInfo/workshopEquipmentList',
+        addDeviceInWorkshop: '/mdc/mdcWorkshopInfo/addWorkshopEquipment',
+        delete2: '/mdc/mdcWorkshopInfo/deleteWorkshopEquipment',
+        deleteBatch2: '/mdc/mdcWorkshopInfo/deleteWorkshopEquipmentBatch',
+      },
+    }
+  },
+  computed: {
+    leftColMd() {
+      return this.selectedRowKeys1.length === 0 ? 24 : 12
+    },
+    rightColMd() {
+      return this.selectedRowKeys1.length === 0 ? 0 : 12
+    },
+  },
+  methods: {
+    onSelectChange2(selectedRowKeys, selectionRows) {
+      this.selectedRowKeys2 = selectedRowKeys
+      this.selectionRows2 = selectionRows
+    },
+    onClearSelected2() {
+      this.selectedRowKeys2 = []
+      this.selectionRows2 = []
+    },
+    onClearSelected1() {
+      this.selectedRowKeys1 = []
+      this.selectionRows1 = []
+    },
+    onSelectChange1(selectedRowKeys, selectionRows) {
+      this.rightcolval = 1
+      this.selectedRowKeys1 = selectedRowKeys
+      this.selectionRows1 = selectionRows
+      this.model1 = Object.assign({}, selectionRows[0])
+      this.currentWorkshopId = selectedRowKeys[0]
+      this.loadData2()
+    },
+    getQueryParams2() {
+      //鑾峰彇鏌ヨ鏉′欢
+      let sqp = {}
+      if (this.superQueryParams2) {
+        sqp['superQueryParams'] = encodeURI(this.superQueryParams2)
+        sqp['superQueryMatchType'] = this.superQueryMatchType2
+      }
+      var param = Object.assign(sqp, this.queryParam2, this.isorter2, this.filters2)
+      param.field = this.getQueryField2()
+      param.pageNo = this.ipagination2.current
+      param.pageSize = this.ipagination2.pageSize
+      return filterObj(param)
+    },
+    getQueryField2() {
+      //TODO 瀛楁鏉冮檺鎺у埗
+      var str = 'id,'
+      this.columns2.forEach(function (value) {
+        str += ',' + value.dataIndex
+      })
+      return str
+    },
+    modalFormOk2() {
+      // 鏂板/淇敼 鎴愬姛鏃讹紝閲嶈浇鍒楄〃
+      this.loadData2()
+    },
+    loadData2(arg) {
+      if (!this.url.list2) {
+        this.$message.error('璇疯缃畊rl.list2灞炴��!')
+        return
+      }
+      //鍔犺浇鏁版嵁 鑻ヤ紶鍏ュ弬鏁�1鍒欏姞杞界涓�椤电殑鍐呭
+      if (arg === 1) {
+        this.ipagination2.current = 1
+      }
+      if (this.currentWorkshopId === '') return
+      let params = this.getQueryParams2() //鏌ヨ鏉′欢
+      params.workshopId = this.currentWorkshopId
+      this.loading2 = true
+      getAction(this.url.list2, params).then((res) => {
+        if (res.success) {
+          this.dataSource2 = res.result.records
+          this.ipagination2.total = res.result.total
+        }else{
+          this.dataSource2=[]
+        }
+        this.loading2 = false
+      })
+    },
+    handleDelete1: function (id) {
+      this.handleDelete(id)
+      this.dataSource2 = []
+      this.currentRoleId = ''
+    },
+
+    /**
+     * 鐐瑰嚮璁惧琛ㄦ牸涓殑鍒犻櫎鎸夐挳鍚庤Е鍙戝垹闄ゅ崟涓溅闂翠笌璁惧鐨勫叧绯�
+     * @param equipmentId 褰撳墠琛岀殑璁惧缂栧彿
+     */
+    handleDelete2: function (equipmentId) {
+      if (!this.url.delete2) {
+        this.$notification.error({
+          message:'娑堟伅',
+          description:'璇疯缃畊rl.delete2灞炴��!'
+        });
+        return
+      }
+      var that = this
+      deleteAction(that.url.delete2, { workshopId: this.currentWorkshopId, equipmentId }).then((res) => {
+        if (res.success) {
+          that.$notification.success({
+            message:'娑堟伅',
+            description:res.message
+          });
+          that.loadData2()
+        } else {
+          that.$notification.warning({
+            message:'娑堟伅',
+            description:res.message
+          });
+        }
+      })
+    },
+
+    /**
+     * 鎵归噺鍒犻櫎杞﹂棿涓庤澶囩殑鍏崇郴
+     */
+    batchDel2: function () {
+      if (!this.url.deleteBatch2) {
+        this.$message.error('璇疯缃畊rl.deleteBatch2灞炴��!')
+        return
+      }
+      if (this.selectedRowKeys2.length <= 0) {
+        // this.$message.warning('璇烽�夋嫨涓�鏉¤褰曪紒')
+        this.$notification.warning({
+          message: '娑堟伅',
+          description: '璇烽�夋嫨涓�鏉¤褰�',
+        })
+        return
+      } else {
+        var ids = ''
+        for (var a = 0; a < this.selectedRowKeys2.length; a++) {
+          ids += this.selectedRowKeys2[a] + ','
+        }
+        var that = this
+        this.$confirm({
+          title: '纭鍒犻櫎',
+          content: '鏄惁鍒犻櫎閫変腑鏁版嵁?',
+          onOk: function () {
+            deleteAction(that.url.deleteBatch2, {
+              workshopId: that.currentWorkshopId,
+              equipmentIds: ids,
+            }).then((res) => {
+              if (res.success) {
+                that.$message.success(res.message)
+                that.loadData2()
+                that.onClearSelected2()
+              } else {
+                that.$message.warning(res.message)
+              }
+            })
+          },
+        })
+      }
+    },
+
+    /**
+     * 閫夋嫨宸叉湁璁惧鍚庣偣鍑荤‘瀹氭椂瑙﹀彂
+     * @param data 宸查�夋嫨鐨勮澶�
+     */
+    selectOK(data) {
+      let params = {}
+      params.workshopId = this.currentWorkshopId
+      params.equipmentIdList = []
+      for (var a = 0; a < data.length; a++) {
+        params.equipmentIdList.push(data[a])
+      }
+      console.log(params)
+      postAction(this.url.addDeviceInWorkshop, params).then((res) => {
+        if (res.success) {
+          this.loadData2()
+          this.$notification.success({
+            message:'娑堟伅',
+            description:res.message
+          });
+        } else {
+          this.$notification.warning({
+            message:'娑堟伅',
+            description:res.message
+          });
+        }
+      })
+    },
+
+    /**
+     * 鐐瑰嚮宸叉湁璁惧鎸夐挳瑙﹀彂
+     */
+    handleAddDeviceInWorkshop() {
+      if (this.currentWorkshopId == '') {
+        this.$message.error('璇烽�夋嫨涓�涓溅闂�!')
+      } else {
+        this.$refs.selectDeviceDrawer.visible = true
+        this.$refs.selectDeviceDrawer.selectedRowKeys = []
+        this.$refs.selectDeviceDrawer.selectedRows = []
+        this.$refs.selectDeviceDrawer.checkedKeys = []
+        this.$refs.selectDeviceDrawer.expandAll()
+      }
+    },
+
+    /**
+     * 鐐瑰嚮褰撳墠琛岃溅闂撮�夐」鍚庤Е鍙戜簨浠�
+     * @param record 褰撳墠琛屾暟鎹�
+     */
+    handleOpen(record) {
+      this.rightcolval = 1
+      this.selectedRowKeys1 = [record.id]
+      this.model1 = Object.assign({}, record)
+      this.currentWorkshopId = record.id
+      this.onClearSelected2()
+      this.loadData2()
+    },
+
+    searchQuery2() {
+      this.loadData2(1)
+    },
+    searchReset2() {
+      this.queryParam2 = {}
+      this.loadData2(1)
+    },
+    handleTableChange2(pagination, filters, sorter) {
+      //鍒嗛〉銆佹帓搴忋�佺瓫閫夊彉鍖栨椂瑙﹀彂
+      //TODO 绛涢��
+      if (Object.keys(sorter).length > 0) {
+        this.isorter2.column = sorter.field
+        this.isorter2.order = 'ascend' == sorter.order ? 'asc' : 'desc'
+      }
+      this.ipagination2 = pagination
+      this.loadData2()
+    },
+    hideUserList() {
+      //this.rightcolval = 0
+      this.selectedRowKeys1 = []
+    },
+  },
+}
+</script>
+<style scoped>
+/** Button鎸夐挳闂磋窛 */
+.ant-btn {
+  margin-left: 8px;
+}
+  .close-circle{
+    position: absolute;
+    z-index: 1;
+    right: 15px;
+    top: 15px;
+    cursor: pointer;
+  }
+</style>
\ No newline at end of file
diff --git a/src/views/system/modules/WorkshopModal.vue b/src/views/system/modules/WorkshopModal.vue
new file mode 100644
index 0000000..2118a6d
--- /dev/null
+++ b/src/views/system/modules/WorkshopModal.vue
@@ -0,0 +1,144 @@
+<template>
+  <a-modal
+    :title="title"
+    :width="800"
+    :visible="visible"
+    :confirmLoading="confirmLoading"
+    @ok="handleOk"
+    @cancel="handleCancel"
+    cancelText="鍏抽棴"
+    wrapClassName="ant-modal-cust-warp"
+    style="top:5%;height: 85%;overflow-y: hidden">
+
+    <a-spin :spinning="confirmLoading">
+      <a-form-model ref="form" v-bind="layout" :model="model" :rules="validatorRules">
+        <a-form-model-item label="杞﹂棿鍚嶇О" required prop="workshopName">
+          <a-input v-model="model.workshopName" placeholder="璇疯緭鍏ヨ溅闂村悕绉�"/>
+        </a-form-model-item>
+        <a-form-model-item label="杞﹂棿鑳屾櫙鍥�" required prop="backgroundImage">
+          <j-image-upload class="avatar-uploader" text="涓婁紶" v-model="model.backgroundImage"></j-image-upload>
+        </a-form-model-item>
+        <a-form-model-item label="璁惧缂栧彿棰滆壊">
+          <a-input type="color" v-model="model.equipmentIdColor"></a-input>
+        </a-form-model-item>
+        <a-form-model-item label="鎺堟潈鏍囪瘑">
+          <a-input placeholder="璇疯緭鍏ユ巿鏉冩爣璇�" v-model="model.perms"/>
+        </a-form-model-item>
+      </a-form-model>
+    </a-spin>
+  </a-modal>
+</template>
+
+<script>
+  import api from '@/api/mdc'
+
+  export default {
+    name: 'WorkshopModal',
+    components: {},
+    data() {
+      return {
+        title: '鎿嶄綔',
+        visible: false,
+        isEdit: false,
+        model: {},
+        layout: {
+          labelCol: { span: 3 },
+          wrapperCol: { span: 14 }
+        },
+        confirmLoading: false,
+        validatorRules: {
+          workshopName: [
+            { required: true, message: '璇疯緭鍏ヨ溅闂村悕绉�!' },
+            { min: 2, max: 30, message: '闀垮害鍦� 2 鍒� 30 涓瓧绗�', trigger: 'blur' }
+          ],
+          id: [
+            { required: true, message: '璇疯緭鍏ヨ溅闂寸紪鍙�!' },
+            { min: 0, max: 64, message: '闀垮害涓嶈秴杩� 64 涓瓧绗�', trigger: 'blur' },
+            { validator: this.validateRoleCode }
+          ],
+          backgroundImage: [
+            { required: true, message: '璇蜂笂浼犺溅闂磋儗鏅浘!' }
+          ]
+        }
+      }
+    },
+    created() {
+      //澶囦唤model鍘熷鍊�
+      this.modelDefault = JSON.parse(JSON.stringify(this.model))
+    },
+    methods: {
+      add() {
+        this.edit(this.modelDefault)
+      },
+      edit(record) {
+        this.model = Object.assign({}, record)
+        this.visible = true
+        //缂栬緫椤甸潰绂佹淇敼瑙掕壊缂栫爜
+        if (this.model.id) {
+          this.isEdit = true
+        } else {
+          this.isEdit = false
+        }
+      },
+      close() {
+        this.$refs.form.clearValidate()
+        this.$emit('close')
+        this.visible = false
+      },
+      handleOk() {
+        const that = this
+        // 瑙﹀彂琛ㄥ崟楠岃瘉
+        this.$refs.form.validate(valid => {
+          if (valid) {
+            console.log('瑙﹀彂')
+            that.confirmLoading = true
+            let obj
+            if (!this.isEdit) {
+              console.log('瑙﹀彂鏂板')
+              obj = api.addWorkshopApi(this.model)
+            } else {
+              console.log('瑙﹀彂淇敼')
+              obj = api.editWorkshopApi(this.model)
+            }
+            obj.then((res) => {
+              if (res.success) {
+                that.$notification.success({
+                  message:'娑堟伅',
+                  description:res.message
+                });
+                that.$emit('ok')
+              } else {
+                that.$notification.warning({
+                  message:'娑堟伅',
+                  description:res.message
+                });
+              }
+            }).finally(() => {
+              that.confirmLoading = false
+              that.close()
+            })
+          } else {
+            return false
+          }
+        })
+      },
+      handleCancel() {
+        this.close()
+      },
+      validateRoleCode(rule, value, callback) {
+        if (/[\u4E00-\u9FA5]/g.test(value)) {
+          callback('杞﹂棿缂栧彿涓嶅彲杈撳叆姹夊瓧!')
+        } else {
+          callback()
+        }
+      }
+    }
+  }
+</script>
+
+<style scoped>
+  .avatar-uploader > .ant-upload {
+    width: 104px;
+    height: 104px;
+  }
+</style>
\ No newline at end of file

--
Gitblit v1.9.3