Commit 7a1b540403a8697eb0eb098289be39c5d729f180
Committed by
xp.Huang
1 parent
c885d453
feat: app端下发命令新增下发类型
Showing
13 changed files
with
1774 additions
and
559 deletions
| ... | ... | @@ -6,7 +6,8 @@ |
| 6 | 6 | <view class="basic-header"> |
| 7 | 7 | <view class="u-flex"> |
| 8 | 8 | <view class="pl-3"> |
| 9 | - <u-icon v-if="deviceDetail.deviceInfo.longitude !== ''" @click="handleClick" name="map-fill"></u-icon> | |
| 9 | + <u-icon v-if="deviceDetail.deviceInfo.longitude !== ''" @click="handleClick" | |
| 10 | + name="map-fill"></u-icon> | |
| 10 | 11 | </view> |
| 11 | 12 | <view class="basic-text text-clip ml-2"> |
| 12 | 13 | {{ deviceDetail.alias ? deviceDetail.alias : deviceDetail.name }} |
| ... | ... | @@ -16,15 +17,11 @@ |
| 16 | 17 | </view> |
| 17 | 18 | </view> |
| 18 | 19 | <!-- 命令下发 设备在线并且不是网关子设备 --> |
| 19 | - <view class="mr-2" v-if="deviceDetail.deviceState === 'ONLINE' && deviceDetail.transportType !== deviceTypeNum.GBT"> | |
| 20 | - <!-- #ifdef MP --> | |
| 21 | - <u-button type="primary" shape="circle" size="mini" text="命令下发" @click="handleMpShowModal" /> | |
| 22 | - <!-- #endif --> | |
| 23 | - <!-- #ifdef APP-PLUS --> | |
| 20 | + <view class="mr-2" | |
| 21 | + v-if="deviceDetail.deviceState === 'ONLINE' && deviceDetail.transportType !== deviceTypeNum.GBT"> | |
| 24 | 22 | <view class="cu-item" @tap="handleAppShowModal" data-target="Modal"> |
| 25 | 23 | <text>命令下发</text> |
| 26 | 24 | </view> |
| 27 | - <!-- #endif --> | |
| 28 | 25 | </view> |
| 29 | 26 | </view> |
| 30 | 27 | <!-- 设备详情 --> |
| ... | ... | @@ -60,369 +57,339 @@ |
| 60 | 57 | </view> |
| 61 | 58 | </view> |
| 62 | 59 | <!-- 命令下发 --> |
| 63 | - <!-- #ifdef APP-PLUS --> | |
| 64 | - <!-- 原生弹窗 封装成子组件无效 --> | |
| 65 | - <view v-show="showNativeModal" class="cu-modal" :class="modalName == 'Modal' ? 'show' : ''"> | |
| 66 | - <view class="cu-dialog"> | |
| 67 | - <view class="app-command-content"> | |
| 68 | - <view class="app-command-text"> | |
| 69 | - <text>命令下发</text> | |
| 70 | - </view> | |
| 71 | - <view class="app-command-type"> | |
| 72 | - <text>下发类型</text> | |
| 73 | - <view class="mr-2"> | |
| 74 | - <radio-group @change="radioChange" class="flex mr-1"> | |
| 75 | - <label v-for="(item, index) in commandTypeList" :key="item.value"> | |
| 76 | - <view class="flex"> | |
| 77 | - <view class="ml-1"> | |
| 78 | - <radio :value="item.value" :checked="index === current" /> | |
| 79 | - </view> | |
| 80 | - <view style="width:10rpx"></view> | |
| 81 | - <view class="ml-1">{{ item.name }}</view> | |
| 82 | - </view> | |
| 83 | - </label> | |
| 84 | - </radio-group> | |
| 85 | - </view> | |
| 86 | - </view> | |
| 87 | - <view class="app-command-body"> | |
| 88 | - <textarea class="app-command-textarea" v-model="inputCommandContent" | |
| 89 | - :placeholder="`请输入下发内容${isShowTCP ? '(字符串格式)' : '(json格式)'}`" /> | |
| 90 | - <u-icon @click="handleCopy(copyTextValue)" v-if="!isShowTCP" name="question-circle" color="#2979ff" | |
| 91 | - size="28" class="ml-10"> | |
| 92 | - </u-icon> | |
| 93 | - </view> | |
| 94 | - <view class="app-command-buttons"> | |
| 95 | - <view class="cancel-button" @click="cancelCommand"><text class="cancel-text">取消</text></view> | |
| 96 | - <view @click="handleAppCommand" class="confrim-button"><text class="confrim-text">确认</text> | |
| 97 | - </view> | |
| 98 | - </view> | |
| 99 | - </view> | |
| 100 | - </view> | |
| 101 | - </view> | |
| 102 | - <!-- #endif --> | |
| 103 | - <!-- #ifdef MP --> | |
| 104 | - <!-- u-modal在app端弹窗层级无法覆盖背景色 --> | |
| 105 | - <mp-command-issuance ref="mpCommandIssuanceRef" :isShowTCP="isShowTCP" :showModal="mpShowModal" | |
| 106 | - :deviceDetail="deviceDetail" @hideModal="hideMpModal" @cancelCommand="cancelCommand" | |
| 107 | - @confirmCommand="confirmCommand"></mp-command-issuance> | |
| 108 | - <!-- #endif --> | |
| 60 | + <!-- 引入三方库,进行mp端和app端同步弹窗 --> | |
| 61 | + <tn-popup v-model="showNativeModal"> | |
| 62 | + <commandIssuanceVue ref="mpCommandIssuanceRef" :isShowTCP="isShowTCP" | |
| 63 | + :deviceDetail="deviceDetail" @hideModal="hideMpModal" @cancelCommand="cancelCommand" | |
| 64 | + @confirmCommand="confirmCommand" /> | |
| 65 | + </tn-popup> | |
| 109 | 66 | </view> |
| 110 | 67 | </template> |
| 111 | 68 | |
| 112 | 69 | <script> |
| 113 | -import { formatToDate } from '@/plugins/utils.js'; | |
| 114 | -import api from '@/api/index.js'; | |
| 115 | -import mpCommandIssuance from './mp-command-issuance.vue'; | |
| 116 | -import { commandTypeList } from '../config/data.js' | |
| 117 | -import { useShowModal } from '@/plugins/utils.js' | |
| 118 | -import { deviceTypeNum } from '../config/data' | |
| 119 | -import deviceDetail from '../device-detail.vue'; | |
| 70 | + import { | |
| 71 | + formatToDate | |
| 72 | + } from '@/plugins/utils.js'; | |
| 73 | + import api from '@/api/index.js'; | |
| 74 | + import mpCommandIssuance from './mp-command-issuance.vue'; | |
| 75 | + import { | |
| 76 | + commandTypeList | |
| 77 | + } from '../config/data.js' | |
| 78 | + import { | |
| 79 | + useShowModal | |
| 80 | + } from '@/plugins/utils.js' | |
| 81 | + import { | |
| 82 | + deviceTypeNum | |
| 83 | + } from '../config/data' | |
| 84 | + import deviceDetail from '../device-detail.vue'; | |
| 85 | + import commandIssuanceVue from './command-issuance.vue'; | |
| 120 | 86 | |
| 121 | -export default { | |
| 122 | - components: { | |
| 123 | - mpCommandIssuance, | |
| 124 | - }, | |
| 125 | - props: { | |
| 126 | - deviceDetail: { | |
| 127 | - type: Object, | |
| 128 | - default: () => ({}) | |
| 129 | - } | |
| 130 | - }, | |
| 131 | - data() { | |
| 132 | - return { | |
| 133 | - showNativeModal: false, | |
| 134 | - current: 0, | |
| 135 | - commandTypeList, | |
| 136 | - deviceTypeNum: deviceTypeNum, | |
| 137 | - commandTypeStr: 'OneWay', | |
| 138 | - inputCommandContent: '', | |
| 139 | - mpShowModal: false, | |
| 140 | - commandValue: {}, | |
| 141 | - isShowTCP: false, //用于下发命令时判断是否是TCP/UDP | |
| 142 | - modalName: null, | |
| 143 | - copyTextValue: { | |
| 144 | - "method": "methodThingskit", | |
| 145 | - "params": { | |
| 146 | - "pin": 7, | |
| 147 | - "value": 1 | |
| 148 | - } | |
| 149 | - } | |
| 150 | - }; | |
| 151 | - }, | |
| 152 | - computed: { | |
| 153 | - deviceStatus() { | |
| 154 | - return this.deviceDetail.deviceState === 'INACTIVE' ? '待激活' : this.deviceDetail.deviceState === 'ONLINE' ? | |
| 155 | - '在线' : '离线'; | |
| 87 | + export default { | |
| 88 | + components: { | |
| 89 | + mpCommandIssuance, | |
| 90 | + commandIssuanceVue | |
| 156 | 91 | }, |
| 157 | - deviceType() { | |
| 158 | - return this.deviceDetail.deviceType === 'DIRECT_CONNECTION' ? | |
| 159 | - '直连设备' : | |
| 160 | - this.deviceDetail.deviceType === 'GATEWAY' ? | |
| 161 | - '网关设备' : | |
| 162 | - this.deviceDetail.deviceType === 'SENSOR' ? | |
| 163 | - '网关子设备' : | |
| 164 | - ''; | |
| 165 | - }, | |
| 166 | - alarmStatus() { | |
| 167 | - return this.deviceDetail.alarmStatus === '0' ? '否' : '是'; | |
| 92 | + props: { | |
| 93 | + deviceDetail: { | |
| 94 | + type: Object, | |
| 95 | + default: () => ({}) | |
| 96 | + } | |
| 168 | 97 | }, |
| 169 | - formatLastOnlineTime() { | |
| 170 | - return formatToDate(Number(this.deviceDetail.lastOnlineTime), 'YYYY-MM-DD HH:mm:ss'); | |
| 171 | - } | |
| 172 | - }, | |
| 173 | - beforeCreate() { | |
| 174 | - this.modalName = null | |
| 175 | - }, | |
| 176 | - onLoad() { | |
| 177 | - // 隐藏原生的tabbar | |
| 178 | - uni.hideTabBar(); | |
| 179 | - this.modalName = null | |
| 180 | - }, | |
| 181 | - methods: { | |
| 182 | - handleCopy(value) { | |
| 183 | - useShowModal(JSON.stringify(value), '命令下发', '复制内容').then(res => { | |
| 184 | - uni.setClipboardData({ | |
| 185 | - data: JSON.stringify(value), | |
| 186 | - success: () => { | |
| 187 | - uni.showToast({ | |
| 188 | - title: '复制成功' | |
| 189 | - }) | |
| 98 | + data() { | |
| 99 | + return { | |
| 100 | + showNativeModal: false, | |
| 101 | + current: 0, | |
| 102 | + commandTypeList, | |
| 103 | + deviceTypeNum: deviceTypeNum, | |
| 104 | + commandTypeStr: 'OneWay', | |
| 105 | + inputCommandContent: '', | |
| 106 | + mpShowModal: false, | |
| 107 | + commandValue: {}, | |
| 108 | + isShowTCP: false, //用于下发命令时判断是否是TCP/UDP | |
| 109 | + modalName: null, | |
| 110 | + copyTextValue: { | |
| 111 | + "method": "methodThingskit", | |
| 112 | + "params": { | |
| 113 | + "pin": 7, | |
| 114 | + "value": 1 | |
| 190 | 115 | } |
| 191 | - }); | |
| 192 | - }) | |
| 193 | - }, | |
| 194 | - radioChange: function (evt) { | |
| 195 | - for (let i = 0; i < this.commandTypeList.length; i++) { | |
| 196 | - if (this.items[i].value === evt.detail.value) { | |
| 197 | - this.current = i; | |
| 198 | - break; | |
| 199 | 116 | } |
| 200 | - } | |
| 201 | - this.commandTypeStr = evt.detail.value | |
| 202 | - }, | |
| 203 | - formatTextStatus(deviceState) { | |
| 204 | - return deviceState === 'INACTIVE' ? '#666' : deviceState === 'ONLINE' ? '#377DFF' : '#DE4437'; | |
| 205 | - }, | |
| 206 | - handleClick() { | |
| 207 | - const data = { | |
| 208 | - longitude: this.deviceDetail.deviceInfo.longitude || 0, | |
| 209 | - latitude: this.deviceDetail.deviceInfo.latitude || 0 | |
| 210 | 117 | }; |
| 211 | - uni.navigateTo({ | |
| 212 | - url: '/device-subpackage/device-detail/device-position?data=' + JSON.stringify(data) | |
| 213 | - }); | |
| 214 | - }, | |
| 215 | - disabledScroll() { | |
| 216 | - return; | |
| 217 | - }, | |
| 218 | - handleAppShowModal(e) { | |
| 219 | - this.modalName = e.currentTarget.dataset.target; | |
| 220 | - this.showNativeModal = true | |
| 221 | - }, | |
| 222 | - handleMpShowModal() { | |
| 223 | - const { | |
| 224 | - transportType | |
| 225 | - } = this.deviceDetail.deviceProfile; | |
| 226 | - this.isShowTCP = transportType == 'TCP' ? true : false; | |
| 227 | - this.mpShowModal = true; | |
| 228 | 118 | }, |
| 229 | - hideMpModal() { | |
| 230 | - this.mpShowModal = false; | |
| 231 | - }, | |
| 232 | - hideAppModal() { | |
| 233 | - this.modalName = null; | |
| 234 | - this.showNativeModal = false | |
| 235 | - }, | |
| 236 | - confirmCommand(commandType, callType, values) { | |
| 237 | - this.handleCommand(commandType, callType, values) | |
| 119 | + computed: { | |
| 120 | + deviceStatus() { | |
| 121 | + return this.deviceDetail.deviceState === 'INACTIVE' ? '待激活' : this.deviceDetail.deviceState === 'ONLINE' ? | |
| 122 | + '在线' : '离线'; | |
| 123 | + }, | |
| 124 | + deviceType() { | |
| 125 | + return this.deviceDetail.deviceType === 'DIRECT_CONNECTION' ? | |
| 126 | + '直连设备' : | |
| 127 | + this.deviceDetail.deviceType === 'GATEWAY' ? | |
| 128 | + '网关设备' : | |
| 129 | + this.deviceDetail.deviceType === 'SENSOR' ? | |
| 130 | + '网关子设备' : | |
| 131 | + ''; | |
| 132 | + }, | |
| 133 | + alarmStatus() { | |
| 134 | + return this.deviceDetail.alarmStatus === '0' ? '否' : '是'; | |
| 135 | + }, | |
| 136 | + formatLastOnlineTime() { | |
| 137 | + return formatToDate(Number(this.deviceDetail.lastOnlineTime), 'YYYY-MM-DD HH:mm:ss'); | |
| 138 | + } | |
| 238 | 139 | }, |
| 239 | - cancelCommand() { | |
| 240 | - this.hideMpModal(); | |
| 241 | - this.hideAppModal(); | |
| 242 | - this.commandTypeStr = 'OneWay' | |
| 243 | - this.inputCommandContent = '' | |
| 244 | - this.$nextTick(() => { | |
| 245 | - this.$refs.mpCommandIssuanceRef.reset() | |
| 246 | - }) | |
| 140 | + beforeCreate() { | |
| 141 | + this.modalName = null | |
| 247 | 142 | }, |
| 248 | - handleAppCommand() { | |
| 249 | - this.handleCommand(this.commandTypeStr, this.inputCommandContent) | |
| 143 | + onLoad() { | |
| 144 | + // 隐藏原生的tabbar | |
| 145 | + uni.hideTabBar(); | |
| 146 | + this.modalName = null | |
| 250 | 147 | }, |
| 251 | - async handleCommand(commandType, callType, values) { | |
| 252 | - if (!values) return uni.$u.toast('请输入下发内容~'); | |
| 253 | - if(callType=='TwoWay'){ | |
| 254 | - const result = await api.deviceApi.getDeviceActiveTime(this.deviceDetail.tbDeviceId) | |
| 255 | - const [firsetItem] = result || [] | |
| 256 | - if (!firsetItem.value) { | |
| 257 | - return uni.$u.toast('当前设备不在线~') | |
| 148 | + methods: { | |
| 149 | + handleCopy(value) { | |
| 150 | + useShowModal(JSON.stringify(value), '命令下发', '复制内容').then(res => { | |
| 151 | + uni.setClipboardData({ | |
| 152 | + data: JSON.stringify(value), | |
| 153 | + success: () => { | |
| 154 | + uni.showToast({ | |
| 155 | + title: '复制成功' | |
| 156 | + }) | |
| 157 | + } | |
| 158 | + }); | |
| 159 | + }) | |
| 160 | + }, | |
| 161 | + radioChange: function(evt) { | |
| 162 | + for (let i = 0; i < this.commandTypeList.length; i++) { | |
| 163 | + if (this.items[i].value === evt.detail.value) { | |
| 164 | + this.current = i; | |
| 165 | + break; | |
| 166 | + } | |
| 258 | 167 | } |
| 259 | - } | |
| 260 | - | |
| 261 | - this.commandValue.persistent = true; | |
| 262 | - this.commandValue.additionalInfo = { | |
| 263 | - cmdType: commandType == 0 ? 0 : 1 | |
| 264 | - }; | |
| 265 | - this.commandValue.method = 'methodThingskit'; | |
| 266 | - this.commandValue.params = values; | |
| 267 | - if (commandType == 0) {//下发类型是自定义时 | |
| 268 | - if (this.isShowTCP) { | |
| 269 | - //TCP的格式只能是字符串 | |
| 270 | - const zg = /^[0-9a-zA-Z]*$/; | |
| 271 | - if (!zg.test(values)) { | |
| 272 | - uni.$u.toast('输入的内容只能是字母和数字的组合'); | |
| 273 | - return; | |
| 168 | + this.commandTypeStr = evt.detail.value | |
| 169 | + }, | |
| 170 | + formatTextStatus(deviceState) { | |
| 171 | + return deviceState === 'INACTIVE' ? '#666' : deviceState === 'ONLINE' ? '#377DFF' : '#DE4437'; | |
| 172 | + }, | |
| 173 | + handleClick() { | |
| 174 | + const data = { | |
| 175 | + longitude: this.deviceDetail.deviceInfo.longitude || 0, | |
| 176 | + latitude: this.deviceDetail.deviceInfo.latitude || 0 | |
| 177 | + }; | |
| 178 | + uni.navigateTo({ | |
| 179 | + url: '/device-subpackage/device-detail/device-position?data=' + JSON.stringify(data) | |
| 180 | + }); | |
| 181 | + }, | |
| 182 | + disabledScroll() { | |
| 183 | + return; | |
| 184 | + }, | |
| 185 | + handleAppShowModal(e) { | |
| 186 | + this.modalName = e.currentTarget.dataset.target; | |
| 187 | + this.showNativeModal = true | |
| 188 | + }, | |
| 189 | + handleMpShowModal() { | |
| 190 | + const { | |
| 191 | + transportType | |
| 192 | + } = this.deviceDetail.deviceProfile; | |
| 193 | + this.isShowTCP = transportType == 'TCP' ? true : false; | |
| 194 | + this.mpShowModal = true; | |
| 195 | + }, | |
| 196 | + hideMpModal() { | |
| 197 | + this.mpShowModal = false; | |
| 198 | + }, | |
| 199 | + hideAppModal() { | |
| 200 | + this.modalName = null; | |
| 201 | + this.showNativeModal = false | |
| 202 | + }, | |
| 203 | + confirmCommand(commandType, callType, values) { | |
| 204 | + this.handleCommand(commandType, callType, values) | |
| 205 | + }, | |
| 206 | + cancelCommand() { | |
| 207 | + this.hideMpModal(); | |
| 208 | + this.hideAppModal(); | |
| 209 | + this.commandTypeStr = 'OneWay' | |
| 210 | + this.inputCommandContent = '' | |
| 211 | + this.$nextTick(() => { | |
| 212 | + this.$refs.mpCommandIssuanceRef.reset() | |
| 213 | + }) | |
| 214 | + }, | |
| 215 | + handleAppCommand() { | |
| 216 | + this.handleCommand(this.commandTypeStr, this.commandTypeStr, this.inputCommandContent) | |
| 217 | + }, | |
| 218 | + async handleCommand(commandType, callType, values) { | |
| 219 | + if (!values) return uni.$u.toast('请输入下发内容~'); | |
| 220 | + if (callType == 'TwoWay') { | |
| 221 | + const result = await api.deviceApi.getDeviceActiveTime(this.deviceDetail.tbDeviceId) | |
| 222 | + const [firsetItem] = result || [] | |
| 223 | + if (!firsetItem.value) { | |
| 224 | + return uni.$u.toast('当前设备不在线~') | |
| 274 | 225 | } |
| 275 | - this.commandValue.params = values; | |
| 276 | - } else { | |
| 277 | - this.commandValue.params = JSON.parse(values); | |
| 278 | 226 | } |
| 279 | - } | |
| 280 | - | |
| 281 | - await api.deviceApi.issueCommand(callType, this.deviceDetail.tbDeviceId, this.commandValue); | |
| 282 | - this.cancelCommand(); | |
| 283 | - uni.$u.toast('下发成功~'); | |
| 284 | - }, | |
| 285 | 227 | |
| 286 | - } | |
| 287 | -}; | |
| 228 | + this.commandValue.persistent = true; | |
| 229 | + this.commandValue.additionalInfo = { | |
| 230 | + cmdType: commandType == 0 ? 0 : 1 | |
| 231 | + }; | |
| 232 | + this.commandValue.method = 'methodThingskit'; | |
| 233 | + this.commandValue.params = values; | |
| 234 | + if (commandType == 0) { //下发类型是自定义时 | |
| 235 | + if (this.isShowTCP) { | |
| 236 | + //TCP的格式只能是字符串 | |
| 237 | + const zg = /^[0-9a-zA-Z]*$/; | |
| 238 | + if (!zg.test(values)) { | |
| 239 | + uni.$u.toast('输入的内容只能是字母和数字的组合'); | |
| 240 | + return; | |
| 241 | + } | |
| 242 | + this.commandValue.params = values; | |
| 243 | + } else { | |
| 244 | + this.commandValue.params = JSON.parse(values); | |
| 245 | + } | |
| 246 | + } | |
| 247 | + | |
| 248 | + await api.deviceApi.issueCommand(callType, this.deviceDetail.tbDeviceId, this.commandValue); | |
| 249 | + this.cancelCommand(); | |
| 250 | + uni.$u.toast('下发成功~'); | |
| 251 | + }, | |
| 252 | + | |
| 253 | + } | |
| 254 | + }; | |
| 288 | 255 | </script> |
| 289 | 256 | |
| 290 | 257 | <style lang="scss" scoped> |
| 291 | -@import url('../static/modal.css'); | |
| 258 | + @import url('../static/modal.css'); | |
| 292 | 259 | |
| 293 | -.app-command-content { | |
| 294 | - .app-command-text { | |
| 295 | - display: flex; | |
| 296 | - justify-content: center; | |
| 297 | - align-items: center; | |
| 260 | + .app-command-content { | |
| 261 | + .app-command-text { | |
| 262 | + display: flex; | |
| 263 | + justify-content: center; | |
| 264 | + align-items: center; | |
| 298 | 265 | |
| 299 | - text { | |
| 300 | - font-weight: 700; | |
| 266 | + text { | |
| 267 | + font-weight: 700; | |
| 268 | + } | |
| 301 | 269 | } |
| 302 | - } | |
| 303 | 270 | |
| 304 | - .app-command-type { | |
| 305 | - display: flex; | |
| 306 | - margin-top: 20rpx; | |
| 307 | - margin-left: 20rpx; | |
| 271 | + .app-command-type { | |
| 272 | + display: flex; | |
| 273 | + margin-top: 20rpx; | |
| 274 | + margin-left: 20rpx; | |
| 308 | 275 | |
| 309 | - text { | |
| 310 | - font-weight: 700; | |
| 276 | + text { | |
| 277 | + font-weight: 700; | |
| 278 | + } | |
| 311 | 279 | } |
| 312 | - } | |
| 313 | 280 | |
| 314 | - .app-command-body { | |
| 315 | - display: flex; | |
| 316 | - align-items: center; | |
| 317 | - justify-content: space-between; | |
| 318 | - margin-top: 20rpx; | |
| 319 | - margin-left: 20rpx; | |
| 281 | + .app-command-body { | |
| 282 | + display: flex; | |
| 283 | + align-items: center; | |
| 284 | + justify-content: space-between; | |
| 285 | + margin-top: 20rpx; | |
| 286 | + margin-left: 20rpx; | |
| 320 | 287 | |
| 321 | - .app-command-textarea { | |
| 322 | - width: 625rpx; | |
| 323 | - height: 400rpx; | |
| 324 | - background: #FFFFFF; | |
| 325 | - box-shadow: 2px 2px 4px 0px rgba(0, 0, 0, 0.03); | |
| 326 | - border-radius: 10px; | |
| 288 | + .app-command-textarea { | |
| 289 | + width: 625rpx; | |
| 290 | + height: 400rpx; | |
| 291 | + background: #FFFFFF; | |
| 292 | + box-shadow: 2px 2px 4px 0px rgba(0, 0, 0, 0.03); | |
| 293 | + border-radius: 10px; | |
| 294 | + } | |
| 327 | 295 | } |
| 328 | - } | |
| 329 | - | |
| 330 | - .app-command-buttons { | |
| 331 | - display: flex; | |
| 332 | - align-items: center; | |
| 333 | - justify-content: space-evenly; | |
| 334 | - height: 85rpx; | |
| 335 | - margin-top: 20rpx; | |
| 336 | - margin-bottom: 20rpx; | |
| 337 | 296 | |
| 338 | - .cancel-button { | |
| 339 | - width: 300rpx; | |
| 340 | - background: #e3e3e5; | |
| 297 | + .app-command-buttons { | |
| 298 | + display: flex; | |
| 299 | + align-items: center; | |
| 300 | + justify-content: space-evenly; | |
| 341 | 301 | height: 85rpx; |
| 342 | - border-radius: 38rpx; | |
| 343 | - line-height: 85rpx; | |
| 302 | + margin-top: 20rpx; | |
| 303 | + margin-bottom: 20rpx; | |
| 344 | 304 | |
| 345 | - .cancel-text { | |
| 346 | - color: #333333 | |
| 305 | + .cancel-button { | |
| 306 | + width: 300rpx; | |
| 307 | + background: #e3e3e5; | |
| 308 | + height: 85rpx; | |
| 309 | + border-radius: 38rpx; | |
| 310 | + line-height: 85rpx; | |
| 311 | + | |
| 312 | + .cancel-text { | |
| 313 | + color: #333333 | |
| 314 | + } | |
| 347 | 315 | } |
| 348 | - } | |
| 349 | 316 | |
| 350 | - .confrim-button { | |
| 351 | - width: 300rpx; | |
| 352 | - background: #3388ff; | |
| 353 | - border-radius: 38rpx; | |
| 354 | - height: 85rpx; | |
| 355 | - line-height: 85rpx; | |
| 317 | + .confrim-button { | |
| 318 | + width: 300rpx; | |
| 319 | + background: #3388ff; | |
| 320 | + border-radius: 38rpx; | |
| 321 | + height: 85rpx; | |
| 322 | + line-height: 85rpx; | |
| 356 | 323 | |
| 357 | - .confrim-text { | |
| 358 | - color: white | |
| 324 | + .confrim-text { | |
| 325 | + color: white | |
| 326 | + } | |
| 359 | 327 | } |
| 360 | 328 | } |
| 361 | 329 | } |
| 362 | -} | |
| 363 | 330 | |
| 364 | -.basic-page { | |
| 365 | - padding: 0 30rpx; | |
| 331 | + .basic-page { | |
| 332 | + padding: 0 30rpx; | |
| 366 | 333 | |
| 367 | - .basic-header { | |
| 368 | - display: flex; | |
| 369 | - justify-content: space-between; | |
| 370 | - align-items: center; | |
| 371 | - height: 140rpx; | |
| 372 | - background-color: #fff; | |
| 373 | - border-radius: 20rpx; | |
| 334 | + .basic-header { | |
| 335 | + display: flex; | |
| 336 | + justify-content: space-between; | |
| 337 | + align-items: center; | |
| 338 | + height: 140rpx; | |
| 339 | + background-color: #fff; | |
| 340 | + border-radius: 20rpx; | |
| 374 | 341 | |
| 375 | - .basic-text { | |
| 376 | - width: 370rpx; | |
| 377 | - } | |
| 342 | + .basic-text { | |
| 343 | + width: 370rpx; | |
| 344 | + } | |
| 378 | 345 | |
| 379 | - .cu-item { | |
| 380 | - background: #3388ff; | |
| 381 | - border-radius: 12px; | |
| 382 | - width: 120rpx; | |
| 383 | - height: 48rpx; | |
| 384 | - text-align: center; | |
| 385 | - line-height: 40rpx; | |
| 346 | + .cu-item { | |
| 347 | + background: #3388ff; | |
| 348 | + border-radius: 12px; | |
| 349 | + width: 120rpx; | |
| 350 | + height: 48rpx; | |
| 351 | + text-align: center; | |
| 352 | + line-height: 40rpx; | |
| 386 | 353 | |
| 387 | - text { | |
| 388 | - font-size: 12px; | |
| 389 | - font-family: PingFangSC-Regular, PingFang SC; | |
| 390 | - font-weight: 400; | |
| 391 | - color: #ffffff; | |
| 354 | + text { | |
| 355 | + font-size: 12px; | |
| 356 | + font-family: PingFangSC-Regular, PingFang SC; | |
| 357 | + font-weight: 400; | |
| 358 | + color: #ffffff; | |
| 359 | + } | |
| 392 | 360 | } |
| 393 | - } | |
| 394 | 361 | |
| 395 | - .basic-text-status { | |
| 396 | - font-size: 14px; | |
| 362 | + .basic-text-status { | |
| 363 | + font-size: 14px; | |
| 364 | + } | |
| 397 | 365 | } |
| 398 | - } | |
| 399 | 366 | |
| 400 | - .detail { | |
| 401 | - background-color: #fff; | |
| 402 | - margin-top: 30rpx; | |
| 403 | - border-radius: 20rpx; | |
| 404 | - width: 690rpx; | |
| 367 | + .detail { | |
| 368 | + background-color: #fff; | |
| 369 | + margin-top: 30rpx; | |
| 370 | + border-radius: 20rpx; | |
| 371 | + width: 690rpx; | |
| 405 | 372 | |
| 406 | - .detail-item { | |
| 407 | - padding: 30rpx; | |
| 408 | - display: flex; | |
| 409 | - align-items: center; | |
| 373 | + .detail-item { | |
| 374 | + padding: 30rpx; | |
| 375 | + display: flex; | |
| 376 | + align-items: center; | |
| 410 | 377 | |
| 411 | - .detail-label { | |
| 412 | - color: #333; | |
| 413 | - font-size: 15px; | |
| 414 | - } | |
| 378 | + .detail-label { | |
| 379 | + color: #333; | |
| 380 | + font-size: 15px; | |
| 381 | + } | |
| 415 | 382 | |
| 416 | - .detail-value { | |
| 417 | - color: #666; | |
| 418 | - font-size: 14px; | |
| 419 | - margin-left: 30rpx; | |
| 383 | + .detail-value { | |
| 384 | + color: #666; | |
| 385 | + font-size: 14px; | |
| 386 | + margin-left: 30rpx; | |
| 387 | + } | |
| 420 | 388 | } |
| 421 | 389 | } |
| 422 | 390 | } |
| 423 | -} | |
| 424 | 391 | |
| 425 | -/deep/ .u-modal__content { | |
| 426 | - padding: 30rpx 0 !important; | |
| 427 | -} | |
| 428 | -</style> | |
| 392 | + /deep/ .u-modal__content { | |
| 393 | + padding: 30rpx 0 !important; | |
| 394 | + } | |
| 395 | +</style> | |
| \ No newline at end of file | ... | ... |
| 1 | +<template> | |
| 2 | + <view class="w-100 modal-content"> | |
| 3 | + <view> | |
| 4 | + <view style="max-height: 560rpx; overflow-y: scroll"> | |
| 5 | + <view class="header-title">命令下发</view> | |
| 6 | + <view class="u-flex"> | |
| 7 | + <text class="type-text">下发类型:</text> | |
| 8 | + <u-radio-group v-model="commandType" placement="row" @change="handleCommand"> | |
| 9 | + <u-radio :customStyle="{ marginRight: '20rpx' }" v-for="item in commandTypeList" | |
| 10 | + activeColor="#3388FF" :label="item.label" :name="item.value" :key="item.value"></u-radio> | |
| 11 | + </u-radio-group> | |
| 12 | + </view> | |
| 13 | + <view class="u-flex" style="margin-top: 28rpx" v-if="commandType == 0"> | |
| 14 | + <text class="type-text">单向/双向:</text> | |
| 15 | + <u-radio-group v-model="callType" placement="row"> | |
| 16 | + <u-radio activeColor="#3388FF" label="单向" name="OneWay"></u-radio> | |
| 17 | + <view style="margin: 0 20rpx"></view> | |
| 18 | + <u-radio activeColor="#3388FF" label="双向" name="TwoWay"></u-radio> | |
| 19 | + </u-radio-group> | |
| 20 | + </view> | |
| 21 | + <view class="u-flex" style="margin-top: 28rpx" v-else> | |
| 22 | + <text class="type-text">服务:</text> | |
| 23 | + <view @click="openService"> | |
| 24 | + <u-input shape="circle" v-model="serviceName" placeholder="请选择服务" disabled disabledColor="#fff" | |
| 25 | + suffixIcon="arrow-down" /> | |
| 26 | + </view> | |
| 27 | + </view> | |
| 28 | + <view class="u-flex" style=" | |
| 29 | + margin-top: 28rpx; | |
| 30 | + flex-direction: column; | |
| 31 | + align-items: flex-start; | |
| 32 | + " v-if="isShowServiceFunctionName && commandType == 1"> | |
| 33 | + <text class="type-text">输入参数:</text> | |
| 34 | + <seriesForm ref="seriesFormRef" :seriesInputData="seriesInputData" :isTCPTransport="isTCPTransport"> | |
| 35 | + </seriesForm> | |
| 36 | + </view> | |
| 37 | + <view class="content-body" v-if="commandType == 0"> | |
| 38 | + <div class="u-flex u-row-between"> | |
| 39 | + <u--textarea :placeholder="`请输入下发内容${ | |
| 40 | + isShowTCP ? '(字符串格式)' : '(json格式)' | |
| 41 | + }`" v-model="inputCommandVal" /> | |
| 42 | + <u-icon v-if="!isShowTCP" @click="handleCopy(copyTextValue)" name="question-circle" | |
| 43 | + color="#2979ff" size="28" class="ml-10"> | |
| 44 | + </u-icon> | |
| 45 | + </div> | |
| 46 | + </view> | |
| 47 | + </view> | |
| 48 | + <view class="button-group"> | |
| 49 | + <view> | |
| 50 | + <u-button :customStyle="{ color: '#333' }" color="#e3e3e5" shape="circle" text="取消" | |
| 51 | + @click="cancelCommand"></u-button> | |
| 52 | + </view> | |
| 53 | + <view> | |
| 54 | + <u-button color="#3388ff" shape="circle" text="确认" @click="confirmCommand"></u-button> | |
| 55 | + </view> | |
| 56 | + </view> | |
| 57 | + </view> | |
| 58 | + <u-picker :show="isShowService" :columns="[ | |
| 59 | + seriesList.map((item) => ({ | |
| 60 | + label: item.functionName, | |
| 61 | + value: item.identifier, | |
| 62 | + callType: item.callType, | |
| 63 | + })), | |
| 64 | + ]" keyName="label" closeOnClickOverlay @cancel="cancelTypeGap" @close="cancelTypeGap" | |
| 65 | + @confirm="handleSelect"></u-picker> | |
| 66 | + </view> | |
| 67 | +</template> | |
| 68 | + | |
| 69 | +<script> | |
| 70 | + import { | |
| 71 | + useShowModal | |
| 72 | + } from "@/plugins/utils.js"; | |
| 73 | + import seriesForm from "./seriesForm.vue"; | |
| 74 | + import api from "@/api/index.js"; | |
| 75 | + | |
| 76 | + export default { | |
| 77 | + components: { | |
| 78 | + seriesForm, | |
| 79 | + }, | |
| 80 | + props: { | |
| 81 | + showModal: Boolean, | |
| 82 | + isShowTCP: Boolean, | |
| 83 | + deviceDetail: Object, | |
| 84 | + }, | |
| 85 | + data() { | |
| 86 | + return { | |
| 87 | + current: 0, | |
| 88 | + commandType: 0, //下发类型 | |
| 89 | + callType: "OneWay", //单双向 | |
| 90 | + serviceName: "", //服务 | |
| 91 | + service: null, //服务 | |
| 92 | + inputCommandVal: "", //自定义命令 | |
| 93 | + isShowService: false, //服务下拉框 | |
| 94 | + isShowServiceFunctionName: false, //选择服务过后的输入参数 | |
| 95 | + copyTextValue: { | |
| 96 | + method: "methodThingskit", | |
| 97 | + params: { | |
| 98 | + pin: 7, | |
| 99 | + value: 1, | |
| 100 | + }, | |
| 101 | + }, | |
| 102 | + commandTypeList: [{ | |
| 103 | + label: "自定义", | |
| 104 | + value: 0 | |
| 105 | + }], | |
| 106 | + seriesList: [], //服务下拉框的数据 | |
| 107 | + boolList: [], | |
| 108 | + enumList: [], | |
| 109 | + seriesInputData: [], | |
| 110 | + isTCPTransport: false, | |
| 111 | + }; | |
| 112 | + }, | |
| 113 | + mounted() { | |
| 114 | + this.getFormInfo(); | |
| 115 | + }, | |
| 116 | + watch: { | |
| 117 | + showModal: { | |
| 118 | + deep: true, | |
| 119 | + handler() { | |
| 120 | + this.commandType = 0; | |
| 121 | + this.serviceName = ""; | |
| 122 | + this.isShowServiceFunctionName = false; | |
| 123 | + }, | |
| 124 | + }, | |
| 125 | + }, | |
| 126 | + methods: { | |
| 127 | + cancelCommand() { | |
| 128 | + this.commandType = 0; | |
| 129 | + this.$emit("cancelCommand"); | |
| 130 | + }, | |
| 131 | + async confirmCommand() { | |
| 132 | + if (this.commandType == 0) { | |
| 133 | + this.$emit( | |
| 134 | + "confirmCommand", | |
| 135 | + this.commandType, | |
| 136 | + this.callType, | |
| 137 | + this.inputCommandVal | |
| 138 | + ); | |
| 139 | + } else { | |
| 140 | + const result = this.$refs.seriesFormRef.handleValidate(); | |
| 141 | + if (!result) { | |
| 142 | + return; | |
| 143 | + } | |
| 144 | + const value = this.$refs.seriesFormRef.getFormField(); | |
| 145 | + const values = this.isTCPTransport ? | |
| 146 | + value.serviceCommand : { | |
| 147 | + [this.service]: value, | |
| 148 | + }; | |
| 149 | + this.$emit("confirmCommand", this.commandType, this.callType, values); | |
| 150 | + } | |
| 151 | + }, | |
| 152 | + handleCopy(value) { | |
| 153 | + useShowModal(JSON.stringify(value), "命令下发", "复制内容").then( | |
| 154 | + (res) => { | |
| 155 | + uni.setClipboardData({ | |
| 156 | + data: JSON.stringify(value), | |
| 157 | + success: () => { | |
| 158 | + uni.showToast({ | |
| 159 | + title: "复制成功", | |
| 160 | + }); | |
| 161 | + }, | |
| 162 | + }); | |
| 163 | + } | |
| 164 | + ); | |
| 165 | + }, | |
| 166 | + | |
| 167 | + async getFormInfo() { | |
| 168 | + const { | |
| 169 | + transportType, | |
| 170 | + deviceType, | |
| 171 | + deviceProfile | |
| 172 | + } = | |
| 173 | + this.deviceDetail || {}; | |
| 174 | + const { | |
| 175 | + profileData: { | |
| 176 | + transportConfiguration: { | |
| 177 | + protocol | |
| 178 | + }, | |
| 179 | + }, | |
| 180 | + } = deviceProfile || {}; | |
| 181 | + this.isTCPTransport = transportType === "TCP"; | |
| 182 | + const isTCPModbus = this.isTCPTransport && protocol === "MODBUS_RTU"; | |
| 183 | + if (isTCPModbus || (this.isTCPTransport && deviceType === "SENSOR")) { | |
| 184 | + this.commandTypeList = | |
| 185 | + this.commandTypeList.length == 2 ? | |
| 186 | + this.commandTypeList.pop() : | |
| 187 | + this.commandTypeList; | |
| 188 | + } else { | |
| 189 | + this.commandTypeList.push({ | |
| 190 | + label: "服务", | |
| 191 | + value: 1 | |
| 192 | + }); | |
| 193 | + this.seriesList = await api.deviceApi.getModelServices( | |
| 194 | + this.deviceDetail | |
| 195 | + ); | |
| 196 | + } | |
| 197 | + }, | |
| 198 | + | |
| 199 | + openService() { | |
| 200 | + this.isShowService = true; | |
| 201 | + }, | |
| 202 | + handleSelect(e) { | |
| 203 | + this.isShowService = false; | |
| 204 | + const { | |
| 205 | + value | |
| 206 | + } = e || {}; | |
| 207 | + this.serviceName = value[0].label; | |
| 208 | + this.service = value[0].value; | |
| 209 | + if (this.service) { | |
| 210 | + this.isShowServiceFunctionName = true; | |
| 211 | + const { | |
| 212 | + functionJson | |
| 213 | + } = | |
| 214 | + this.seriesList.filter( | |
| 215 | + (item) => item.identifier === this.service | |
| 216 | + )[0] || {}; | |
| 217 | + const { | |
| 218 | + inputData | |
| 219 | + } = functionJson || {}; | |
| 220 | + this.seriesInputData = inputData || []; | |
| 221 | + this.callType = value[0].callType === "ASYNC" ? "OneWay" : "TwoWay"; | |
| 222 | + } | |
| 223 | + }, | |
| 224 | + | |
| 225 | + cancelModel() { | |
| 226 | + this.isShowService = false; | |
| 227 | + this.seriesInputData = []; | |
| 228 | + this.seriesList = []; | |
| 229 | + }, | |
| 230 | + | |
| 231 | + handleCommand(name) { | |
| 232 | + this.seriesInputData = []; | |
| 233 | + this.serviceName = ""; | |
| 234 | + this.isShowServiceFunctionName = false; | |
| 235 | + if (this.commandType == 0) { | |
| 236 | + this.callType = "OneWay"; | |
| 237 | + } | |
| 238 | + }, | |
| 239 | + | |
| 240 | + cancelTypeGap() { | |
| 241 | + this.isShowService = false; | |
| 242 | + }, | |
| 243 | + | |
| 244 | + reset() { | |
| 245 | + this.callType = "OneWay"; | |
| 246 | + this.inputCommandVal = ""; | |
| 247 | + }, | |
| 248 | + }, | |
| 249 | + }; | |
| 250 | +</script> | |
| 251 | + | |
| 252 | +<style lang="scss" scoped> | |
| 253 | + .modal-content { | |
| 254 | + width: 720rpx; | |
| 255 | + padding: 0 30rpx; | |
| 256 | + background-color: white; | |
| 257 | + | |
| 258 | + .header-title { | |
| 259 | + text-align: center; | |
| 260 | + font-weight: 700; | |
| 261 | + margin-bottom: 40rpx; | |
| 262 | + } | |
| 263 | + | |
| 264 | + .type-text { | |
| 265 | + color: #333; | |
| 266 | + font-size: 14px; | |
| 267 | + font-weight: 700; | |
| 268 | + margin-right: 30rpx; | |
| 269 | + } | |
| 270 | + | |
| 271 | + .content-body { | |
| 272 | + margin-top: 28rpx; | |
| 273 | + width: 100%; | |
| 274 | + } | |
| 275 | + | |
| 276 | + .button-group { | |
| 277 | + display: flex; | |
| 278 | + margin-top: 40rpx; | |
| 279 | + justify-content: space-between; | |
| 280 | + | |
| 281 | + view { | |
| 282 | + width: 300rpx; | |
| 283 | + } | |
| 284 | + } | |
| 285 | + } | |
| 286 | +</style> | |
| \ No newline at end of file | ... | ... |
| 1 | 1 | <template> |
| 2 | - <view class="mp-u-modal"> | |
| 3 | - <u-modal :mask-close-able="true" :show="showModal" closeOnClickOverlay :showConfirmButton="false" @close="$emit('hideModal')" z-index="99999"> | |
| 4 | - <view class="w-100 modal-content"> | |
| 5 | - <view style="max-height:560rpx;overflow-y: scroll;"> | |
| 6 | - <view class="header-title">命令下发</view> | |
| 7 | - <view class="u-flex"> | |
| 8 | - <text class="type-text">下发类型:</text> | |
| 9 | - <u-radio-group v-model="commandType" placement="row" @change="handleCommand"> | |
| 10 | - <u-radio :customStyle="{marginRight: '20rpx'}" v-for="item in commandTypeList" activeColor="#3388FF" :label="item.label" :name="item.value" :key="item.value"></u-radio> | |
| 11 | - </u-radio-group> | |
| 12 | - </view> | |
| 13 | - <view class="u-flex" style="margin-top: 28rpx" v-if="commandType == 0"> | |
| 14 | - <text class="type-text">单向/双向:</text> | |
| 15 | - <u-radio-group v-model="callType" placement="row"> | |
| 16 | - <u-radio activeColor="#3388FF" label="单向" name="OneWay"></u-radio> | |
| 17 | - <view style="margin: 0 20rpx"></view> | |
| 18 | - <u-radio activeColor="#3388FF" label="双向" name="TwoWay"></u-radio> | |
| 19 | - </u-radio-group> | |
| 20 | - </view> | |
| 21 | - <view class="u-flex" style="margin-top: 28rpx" v-else> | |
| 22 | - <text class="type-text">服务:</text> | |
| 23 | - <view @click="openService"> | |
| 24 | - <u-input shape="circle" v-model="serviceName" placeholder="请选择服务" disabled disabledColor="#fff" suffixIcon="arrow-down" /> | |
| 25 | - </view> | |
| 26 | - </view> | |
| 27 | - <view class="u-flex" style="margin-top: 28rpx; flex-direction: column; align-items: flex-start" v-if="isShowServiceFunctionName && commandType == 1"> | |
| 28 | - <text class="type-text">输入参数:</text> | |
| 29 | - <seriesForm ref="seriesFormRef" :seriesInputData="seriesInputData" :isTCPTransport="isTCPTransport"></seriesForm> | |
| 30 | - </view> | |
| 31 | - <view class="content-body" v-if="commandType == 0"> | |
| 32 | - <div class="u-flex u-row-between"> | |
| 33 | - <u--textarea :placeholder="`请输入下发内容${isShowTCP ? '(字符串格式)' : '(json格式)'}`" v-model="inputCommandVal" /> | |
| 34 | - <u-icon v-if="!isShowTCP" @click="handleCopy(copyTextValue)" name="question-circle" color="#2979ff" size="28" class="ml-10"> </u-icon> | |
| 35 | - </div> | |
| 36 | - </view> | |
| 37 | - </view> | |
| 38 | - <view class="button-group"> | |
| 39 | - <view> | |
| 40 | - <u-button :customStyle="{ color: '#333' }" color="#e3e3e5" shape="circle" text="取消" @click="cancelCommand"></u-button> | |
| 41 | - </view> | |
| 42 | - <view> | |
| 43 | - <u-button color="#3388ff" shape="circle" text="确认" @click="confirmCommand"></u-button> | |
| 44 | - </view> | |
| 45 | - </view> | |
| 46 | - </view> | |
| 47 | - <u-picker | |
| 48 | - :show="isShowService" | |
| 49 | - :columns="[seriesList.map((item) => ({ label: item.functionName, value: item.identifier,callType:item.callType }))]" | |
| 50 | - keyName="label" | |
| 51 | - closeOnClickOverlay | |
| 52 | - @cancel="cancelTypeGap" | |
| 53 | - @close="cancelTypeGap" | |
| 54 | - @confirm="handleSelect" | |
| 55 | - ></u-picker> | |
| 56 | - </u-modal> | |
| 57 | - </view> | |
| 2 | + <view class="mp-u-modal"> | |
| 3 | + <u-modal :mask-close-able="true" :show="showModal" closeOnClickOverlay :showConfirmButton="false" | |
| 4 | + @close="$emit('hideModal')" z-index="99999"> | |
| 5 | + <commandIssuance :isShowTCP="isShowTCP" :deviceDetail="deviceDetail" /> | |
| 6 | + </u-modal> | |
| 7 | + </view> | |
| 58 | 8 | </template> |
| 59 | 9 | |
| 60 | 10 | <script> |
| 61 | -import { useShowModal } from '@/plugins/utils.js' | |
| 62 | -import seriesForm from './seriesForm.vue' | |
| 63 | - | |
| 64 | -import api from '@/api/index.js' | |
| 65 | - | |
| 66 | -export default { | |
| 67 | - components: { | |
| 68 | - seriesForm, | |
| 69 | - }, | |
| 70 | - props: { | |
| 71 | - showModal: Boolean, | |
| 72 | - isShowTCP: Boolean, | |
| 73 | - deviceDetail: Object, | |
| 74 | - }, | |
| 75 | - data() { | |
| 76 | - return { | |
| 77 | - current: 0, | |
| 78 | - commandType: 0, //下发类型 | |
| 79 | - callType: 'OneWay', //单双向 | |
| 80 | - serviceName: '', //服务 | |
| 81 | - service: null, //服务 | |
| 82 | - inputCommandVal: '',//自定义命令 | |
| 83 | - isShowService: false, //服务下拉框 | |
| 84 | - isShowServiceFunctionName: false, //选择服务过后的输入参数 | |
| 85 | - copyTextValue: { | |
| 86 | - method: 'methodThingskit', | |
| 87 | - params: { | |
| 88 | - pin: 7, | |
| 89 | - value: 1, | |
| 90 | - }, | |
| 91 | - }, | |
| 92 | - commandTypeList: [{ label: '自定义', value: 0 }], | |
| 93 | - seriesList: [], //服务下拉框的数据 | |
| 94 | - boolList: [], | |
| 95 | - enumList: [], | |
| 96 | - seriesInputData: [], | |
| 97 | - isTCPTransport:false | |
| 98 | - } | |
| 99 | - }, | |
| 100 | - mounted() { | |
| 101 | - this.getFormInfo() | |
| 102 | - }, | |
| 103 | - watch: { | |
| 104 | - showModal: { | |
| 105 | - deep: true, | |
| 106 | - handler() { | |
| 107 | - this.commandType = 0 | |
| 108 | - this.serviceName = '' | |
| 109 | - this.isShowServiceFunctionName = false | |
| 110 | - }, | |
| 111 | - }, | |
| 112 | - }, | |
| 113 | - methods: { | |
| 114 | - cancelCommand() { | |
| 115 | - this.commandType = 0 | |
| 116 | - this.$emit('cancelCommand') | |
| 117 | - }, | |
| 118 | - async confirmCommand() { | |
| 119 | - if(this.commandType==0){ | |
| 120 | - this.$emit('confirmCommand',this.commandType, this.callType, this.inputCommandVal) | |
| 121 | - }else{ | |
| 122 | - const result = this.$refs.seriesFormRef.handleValidate() | |
| 123 | - if(!result){ | |
| 124 | - return | |
| 125 | - } | |
| 126 | - const value = this.$refs.seriesFormRef.getFormField() | |
| 127 | - const values =this.isTCPTransport?value.serviceCommand: { | |
| 128 | - [this.service]:value | |
| 129 | - } | |
| 130 | - this.$emit('confirmCommand',this.commandType, this.callType, values) | |
| 131 | - } | |
| 132 | - }, | |
| 133 | - handleCopy(value) { | |
| 134 | - useShowModal(JSON.stringify(value), '命令下发', '复制内容').then((res) => { | |
| 135 | - uni.setClipboardData({ | |
| 136 | - data: JSON.stringify(value), | |
| 137 | - success: () => { | |
| 138 | - uni.showToast({ | |
| 139 | - title: '复制成功', | |
| 140 | - }) | |
| 141 | - }, | |
| 142 | - }) | |
| 143 | - }) | |
| 144 | - }, | |
| 145 | - | |
| 146 | - async getFormInfo() { | |
| 147 | - const { transportType, deviceType, deviceProfile } = this.deviceDetail || {} | |
| 148 | - const { | |
| 149 | - profileData: { | |
| 150 | - transportConfiguration: { protocol }, | |
| 151 | - }, | |
| 152 | - } = deviceProfile || {} | |
| 153 | - this.isTCPTransport = transportType === 'TCP' | |
| 154 | - const isTCPModbus = this.isTCPTransport && protocol === 'MODBUS_RTU' | |
| 155 | - if (isTCPModbus || (this.isTCPTransport && deviceType === 'SENSOR')) { | |
| 156 | - this.commandTypeList = this.commandTypeList.length==2?this.commandTypeList.pop():this.commandTypeList | |
| 157 | - } else { | |
| 158 | - this.commandTypeList.push({ label: '服务', value: 1 }) | |
| 159 | - this.seriesList = await api.deviceApi.getModelServices(this.deviceDetail) | |
| 160 | - } | |
| 161 | - }, | |
| 162 | - | |
| 163 | - openService() { | |
| 164 | - this.isShowService = true | |
| 165 | - }, | |
| 166 | - handleSelect(e) { | |
| 167 | - this.isShowService = false | |
| 168 | - const { value } = e || {} | |
| 169 | - this.serviceName = value[0].label | |
| 170 | - this.service = value[0].value | |
| 171 | - if (this.service) { | |
| 172 | - this.isShowServiceFunctionName = true | |
| 173 | - const { functionJson } = this.seriesList.filter((item) => item.identifier === this.service)[0] || {} | |
| 174 | - const { inputData } = functionJson || {} | |
| 175 | - this.seriesInputData = inputData || [] | |
| 176 | - this.callType = value[0].callType==='ASYNC'?'OneWay':'TwoWay' | |
| 177 | - } | |
| 178 | - }, | |
| 179 | - | |
| 180 | - cancelModel() { | |
| 181 | - this.isShowService = false | |
| 182 | - this.seriesInputData = [] | |
| 183 | - this.seriesList = [] | |
| 184 | - }, | |
| 185 | - | |
| 186 | - handleCommand(name){ | |
| 187 | - this.seriesInputData = [] | |
| 188 | - this.serviceName = '' | |
| 189 | - this.isShowServiceFunctionName = false | |
| 190 | - if(this.commandType==0){ | |
| 191 | - this.callType = 'OneWay' | |
| 192 | - } | |
| 193 | - }, | |
| 194 | - | |
| 195 | - cancelTypeGap() { | |
| 196 | - this.isShowService = false | |
| 197 | - }, | |
| 198 | - | |
| 199 | - reset() { | |
| 200 | - this.callType = 'OneWay' | |
| 201 | - this.inputCommandVal = '' | |
| 202 | - }, | |
| 203 | - }, | |
| 204 | -} | |
| 11 | + import commandIssuance from "./command-issuance.vue"; | |
| 12 | + | |
| 13 | + export default { | |
| 14 | + components: { | |
| 15 | + commandIssuance, | |
| 16 | + }, | |
| 17 | + props: { | |
| 18 | + showModal: Boolean, | |
| 19 | + isShowTCP: Boolean, | |
| 20 | + deviceDetail: Object, | |
| 21 | + }, | |
| 22 | + }; | |
| 205 | 23 | </script> |
| 206 | 24 | |
| 207 | -<style lang="scss" scoped> | |
| 208 | -.modal-content { | |
| 209 | - width: 720rpx; | |
| 210 | - padding: 0 30rpx; | |
| 211 | - background-color: white; | |
| 212 | - | |
| 213 | - .header-title { | |
| 214 | - text-align: center; | |
| 215 | - font-weight: 700; | |
| 216 | - margin-bottom: 40rpx; | |
| 217 | - } | |
| 218 | - | |
| 219 | - .type-text { | |
| 220 | - color: #333; | |
| 221 | - font-size: 14px; | |
| 222 | - font-weight: 700; | |
| 223 | - margin-right: 30rpx; | |
| 224 | - } | |
| 225 | - | |
| 226 | - .content-body { | |
| 227 | - margin-top: 28rpx; | |
| 228 | - width: 100%; | |
| 229 | - } | |
| 230 | - | |
| 231 | - .button-group { | |
| 232 | - display: flex; | |
| 233 | - margin-top: 40rpx; | |
| 234 | - justify-content: space-between; | |
| 235 | - | |
| 236 | - view { | |
| 237 | - width: 300rpx; | |
| 238 | - } | |
| 239 | - } | |
| 240 | -} | |
| 241 | -</style> | |
| 25 | +<style lang="scss" scoped></style> | |
| \ No newline at end of file | ... | ... |
| ... | ... | @@ -24,7 +24,7 @@ |
| 24 | 24 | suffixIcon="arrow-down" |
| 25 | 25 | /> |
| 26 | 26 | <u-picker |
| 27 | - :show="item.isShowModel" | |
| 27 | + :show="showPickerView" | |
| 28 | 28 | :columns="[boolList]" |
| 29 | 29 | keyName="label" |
| 30 | 30 | @cancel="handleCancelBool(index)" |
| ... | ... | @@ -42,7 +42,7 @@ |
| 42 | 42 | suffixIcon="arrow-down" |
| 43 | 43 | /> |
| 44 | 44 | <u-picker |
| 45 | - :show="item.isShowModel" | |
| 45 | + :show="showPickerView" | |
| 46 | 46 | :columns="[enumList.map((item) => ({ label: item.name, value: item.value }))]" |
| 47 | 47 | keyName="label" |
| 48 | 48 | @cancel="handleCancelEnum(index)" |
| ... | ... | @@ -82,6 +82,7 @@ export default { |
| 82 | 82 | }, |
| 83 | 83 | data() { |
| 84 | 84 | return { |
| 85 | + showPickerView:false, | |
| 85 | 86 | boolInfo: {}, |
| 86 | 87 | enumInfo: {}, |
| 87 | 88 | seriesForm: {}, |
| ... | ... | @@ -178,12 +179,12 @@ export default { |
| 178 | 179 | handleBool(name, dataType, num) { |
| 179 | 180 | this.seriesFunctionList.forEach((item, index) => { |
| 180 | 181 | if (index == num) { |
| 181 | - item.isShowModel = true | |
| 182 | + this.showPickerView = true | |
| 183 | + item.isShowModel = true | |
| 182 | 184 | } |
| 183 | 185 | }) |
| 184 | 186 | const { specs } = dataType || {} |
| 185 | 187 | const { boolClose, boolOpen } = specs || {} |
| 186 | - console.log(boolClose, boolOpen,'boolClose, boolOpen') | |
| 187 | 188 | if(!boolClose&&!boolOpen){ |
| 188 | 189 | uni.$u.toast(`暂无可选的${name}`) |
| 189 | 190 | this.boolList = [] |
| ... | ... | @@ -201,6 +202,7 @@ export default { |
| 201 | 202 | this.seriesFunctionList.forEach((item, index) => { |
| 202 | 203 | if (index == num) { |
| 203 | 204 | item.isShowModel = false |
| 205 | + this.showPickerView = false | |
| 204 | 206 | } |
| 205 | 207 | }) |
| 206 | 208 | }, |
| ... | ... | @@ -220,6 +222,7 @@ export default { |
| 220 | 222 | this.seriesFunctionList.forEach((item, index) => { |
| 221 | 223 | if (index == num) { |
| 222 | 224 | item.isShowModel = true |
| 225 | + this.showPickerView = true | |
| 223 | 226 | } |
| 224 | 227 | }) |
| 225 | 228 | }, |
| ... | ... | @@ -231,6 +234,7 @@ export default { |
| 231 | 234 | this.seriesFunctionList.forEach((item, index) => { |
| 232 | 235 | if (index == num) { |
| 233 | 236 | item.isShowModel = false |
| 237 | + this.showPickerView = false | |
| 234 | 238 | } |
| 235 | 239 | }) |
| 236 | 240 | }, |
| ... | ... | @@ -241,6 +245,7 @@ export default { |
| 241 | 245 | this.seriesFunctionList.forEach((item, index) => { |
| 242 | 246 | if (index == num) { |
| 243 | 247 | item.isShowModel = false |
| 248 | + this.showPickerView = false | |
| 244 | 249 | } |
| 245 | 250 | }) |
| 246 | 251 | }, |
| ... | ... | @@ -248,6 +253,7 @@ export default { |
| 248 | 253 | this.seriesFunctionList.forEach((item, index) => { |
| 249 | 254 | if (index == num) { |
| 250 | 255 | item.isShowModel = false |
| 256 | + this.showPickerView = false | |
| 251 | 257 | } |
| 252 | 258 | }) |
| 253 | 259 | }, | ... | ... |
| ... | ... | @@ -15,7 +15,7 @@ |
| 15 | 15 | suffixIcon="arrow-down" |
| 16 | 16 | /> |
| 17 | 17 | <u-picker |
| 18 | - :show="item.isShowModel" | |
| 18 | + :show="showPickerView" | |
| 19 | 19 | :columns="[boolList]" |
| 20 | 20 | keyName="label" |
| 21 | 21 | closeOnClickOverlay |
| ... | ... | @@ -36,7 +36,7 @@ |
| 36 | 36 | suffixIcon="arrow-down" |
| 37 | 37 | /> |
| 38 | 38 | <u-picker |
| 39 | - :show="item.isShowModel" | |
| 39 | + :show="showPickerView" | |
| 40 | 40 | :columns="[enumList.map((item) => ({ label: item.name, value: item.value }))]" |
| 41 | 41 | keyName="label" |
| 42 | 42 | closeOnClickOverlay |
| ... | ... | @@ -61,6 +61,7 @@ export default { |
| 61 | 61 | }, |
| 62 | 62 | data() { |
| 63 | 63 | return { |
| 64 | + showPickerView: false, | |
| 64 | 65 | boolInfo: {}, |
| 65 | 66 | enumInfo: {}, |
| 66 | 67 | seriesForm: {}, |
| ... | ... | @@ -89,6 +90,7 @@ export default { |
| 89 | 90 | this.seriesFunctionList = this.seriesInputData |
| 90 | 91 | this.seriesInputData.forEach((item) => { |
| 91 | 92 | this.$set(item, 'isShowModel', false) |
| 93 | + this.showPickerView=false | |
| 92 | 94 | const { |
| 93 | 95 | dataType: { specs, type }, |
| 94 | 96 | identifier, |
| ... | ... | @@ -136,6 +138,7 @@ export default { |
| 136 | 138 | this.seriesFunctionList.forEach((item, index) => { |
| 137 | 139 | if (index == num) { |
| 138 | 140 | item.isShowModel = true |
| 141 | + this.showPickerView=true | |
| 139 | 142 | } |
| 140 | 143 | }) |
| 141 | 144 | const { specs } = dataType || {} |
| ... | ... | @@ -154,6 +157,7 @@ export default { |
| 154 | 157 | this.seriesFunctionList.forEach((item, index) => { |
| 155 | 158 | if (index == num) { |
| 156 | 159 | item.isShowModel = false |
| 160 | + this.showPickerView=false | |
| 157 | 161 | } |
| 158 | 162 | }) |
| 159 | 163 | }, |
| ... | ... | @@ -176,6 +180,7 @@ export default { |
| 176 | 180 | this.seriesFunctionList.forEach((item, index) => { |
| 177 | 181 | if (index == num) { |
| 178 | 182 | item.isShowModel = true |
| 183 | + this.showPickerView=true | |
| 179 | 184 | } |
| 180 | 185 | }) |
| 181 | 186 | }, |
| ... | ... | @@ -186,6 +191,7 @@ export default { |
| 186 | 191 | this.seriesFunctionList.forEach((item, index) => { |
| 187 | 192 | if (index == num) { |
| 188 | 193 | item.isShowModel = false |
| 194 | + this.showPickerView=false | |
| 189 | 195 | } |
| 190 | 196 | }) |
| 191 | 197 | }, |
| ... | ... | @@ -193,6 +199,7 @@ export default { |
| 193 | 199 | this.seriesFunctionList.forEach((item, index) => { |
| 194 | 200 | if (index == num) { |
| 195 | 201 | item.isShowModel = false |
| 202 | + this.showPickerView=false | |
| 196 | 203 | } |
| 197 | 204 | }) |
| 198 | 205 | }, | ... | ... |
uni_modules/tn-popup/changelog.md
0 → 100644
uni_modules/tn-popup/color.js
0 → 100644
| 1 | +let color = [ | |
| 2 | + 'red', | |
| 3 | + 'purplered', | |
| 4 | + 'purple', | |
| 5 | + 'bluepurple', | |
| 6 | + 'aquablue', | |
| 7 | + 'blue', | |
| 8 | + 'indigo', | |
| 9 | + 'cyan', | |
| 10 | + 'teal', | |
| 11 | + 'green', | |
| 12 | + 'yellowgreen', | |
| 13 | + 'lime', | |
| 14 | + 'yellow', | |
| 15 | + 'orangeyellow', | |
| 16 | + 'orange', | |
| 17 | + 'orangered', | |
| 18 | + 'brown', | |
| 19 | + 'grey', | |
| 20 | + 'gray' | |
| 21 | +] | |
| 22 | + | |
| 23 | +// 酷炫颜色的数量 | |
| 24 | +const COOL_BG_COLOR_COUNT = 16 | |
| 25 | + | |
| 26 | +/** | |
| 27 | + * 获取图鸟配色颜色列表 | |
| 28 | + */ | |
| 29 | +function getTuniaoColorList() { | |
| 30 | + return color | |
| 31 | +} | |
| 32 | + | |
| 33 | +/** | |
| 34 | + * 获取指定类型的随机颜色对应的类 | |
| 35 | + * @param {String} type 颜色类型 | |
| 36 | + */ | |
| 37 | +function getRandomColorClass(type = 'bg') { | |
| 38 | + const index = Math.floor(Math.random() * color.length) | |
| 39 | + const colorValue = color[index] | |
| 40 | + | |
| 41 | + return 'tn-' + type + '-' + colorValue | |
| 42 | +} | |
| 43 | + | |
| 44 | +/** | |
| 45 | + * 随机获取酷炫背景对应的类 | |
| 46 | + */ | |
| 47 | +function getRandomCoolBgClass() { | |
| 48 | + const index = (Math.random() * COOL_BG_COLOR_COUNT) + 1 | |
| 49 | + return 'tn-cool-bg-color-' + Math.floor(index) | |
| 50 | +} | |
| 51 | + | |
| 52 | +/** | |
| 53 | + * 根据传入的值获取内部背景颜色类 | |
| 54 | + * | |
| 55 | + * @param {String} backgroundColor 背景颜色信息 | |
| 56 | + */ | |
| 57 | +function getBackgroundColorInternalClass(backgroundColor = '') { | |
| 58 | + if (!backgroundColor) return '' | |
| 59 | + | |
| 60 | + if (['tn-bg', 'tn-dynamic-bg', 'tn-main-gradient', 'tn-cool-bg'].some(item => { | |
| 61 | + return backgroundColor.includes(item) | |
| 62 | + })) { | |
| 63 | + return backgroundColor | |
| 64 | + } | |
| 65 | + return '' | |
| 66 | +} | |
| 67 | + | |
| 68 | +/** | |
| 69 | + * 根据传入的值获取背景颜色样式 | |
| 70 | + * | |
| 71 | + * @param {String} backgroundColor 背景颜色信息 | |
| 72 | + */ | |
| 73 | +function getBackgroundColorStyle(backgroundColor = '') { | |
| 74 | + if (!backgroundColor) return '' | |
| 75 | + | |
| 76 | + if (!backgroundColor.startsWith('tn-') || ['#', 'rgb', 'rgba'].some(item => { | |
| 77 | + return backgroundColor.includes(item) | |
| 78 | + })) { | |
| 79 | + return backgroundColor | |
| 80 | + } | |
| 81 | + return '' | |
| 82 | +} | |
| 83 | + | |
| 84 | +/** | |
| 85 | + * 根据传入的值获取内部字体颜色类 | |
| 86 | + * | |
| 87 | + * @param {String} fontColor 背景颜色信息 | |
| 88 | + */ | |
| 89 | +function getFontColorInternalClass(fontColor = '') { | |
| 90 | + if (!fontColor) return '' | |
| 91 | + | |
| 92 | + if (['tn-color'].some(item => { | |
| 93 | + return fontColor.includes(item) | |
| 94 | + })) { | |
| 95 | + return fontColor | |
| 96 | + } | |
| 97 | + return '' | |
| 98 | +} | |
| 99 | + | |
| 100 | +/** | |
| 101 | + * 根据传入的值获取字体颜色样式 | |
| 102 | + * | |
| 103 | + * @param {String} fontColor 背景颜色信息 | |
| 104 | + */ | |
| 105 | +function getFontColorStyle(fontColor = '') { | |
| 106 | + if (!fontColor) return '' | |
| 107 | + | |
| 108 | + if (!fontColor.startsWith('tn-') || ['#', 'rgb', 'rgba'].some(item => { | |
| 109 | + return fontColor.includes(item) | |
| 110 | + })) { | |
| 111 | + return fontColor | |
| 112 | + } | |
| 113 | + return '' | |
| 114 | +} | |
| 115 | + | |
| 116 | +/** | |
| 117 | + * 求两个颜色之间的渐变值 | |
| 118 | + * | |
| 119 | + * @param {String} startColor 开始颜色 | |
| 120 | + * @param {String} endColor 结束颜色 | |
| 121 | + * @param {Number} step 颜色等分的份额 | |
| 122 | + */ | |
| 123 | +function colorGradient(startColor = 'rgb(0, 0, 0)', endColor='rgb(255, 255, 255)', step = 10) { | |
| 124 | + let startRGB = hexToRGB(startColor, false) | |
| 125 | + let startR = startRGB[0] | |
| 126 | + let startG = startRGB[1] | |
| 127 | + let startB = startRGB[2] | |
| 128 | + | |
| 129 | + let endRGB = hexToRGB(endColor, false) | |
| 130 | + let endR = endRGB[0] | |
| 131 | + let endG = endRGB[1] | |
| 132 | + let endB = endRGB[2] | |
| 133 | + | |
| 134 | + // 求差值 | |
| 135 | + let R = (endR - startR) / step | |
| 136 | + let G = (endG - startG) / step | |
| 137 | + let B = (endB - startB) / step | |
| 138 | + | |
| 139 | + let colorArr = [] | |
| 140 | + for (let i = 0; i < step; i++) { | |
| 141 | + // 计算每一步的hex值 | |
| 142 | + let hex = rgbToHex(`rgb(${Math.round(R * i + startR)}, ${Math.round(G * i + startG)}, ${Math.round(B * i + startB)})`) | |
| 143 | + colorArr.push(hex) | |
| 144 | + } | |
| 145 | + return colorArr | |
| 146 | +} | |
| 147 | + | |
| 148 | +/** | |
| 149 | + * 将hex的颜色表示方式转换为rgb表示方式 | |
| 150 | + * | |
| 151 | + * @param {String} color 颜色 | |
| 152 | + * @param {Boolean} str 是否返回字符串 | |
| 153 | + * @return {Array|String} rgb的值 | |
| 154 | + */ | |
| 155 | +function hexToRGB(color, str = true) { | |
| 156 | + let reg = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/ | |
| 157 | + | |
| 158 | + color = color.toLowerCase() | |
| 159 | + if (color && reg.test(color)) { | |
| 160 | + // #000 => #000000 | |
| 161 | + if (color.length === 4) { | |
| 162 | + let colorNew = '#' | |
| 163 | + for (let i = 1; i < 4; i++) { | |
| 164 | + colorNew += color.slice(i, i + 1).concat(color.slice(i, i + 1)) | |
| 165 | + } | |
| 166 | + color = colorNew | |
| 167 | + } | |
| 168 | + // 处理六位的颜色值 | |
| 169 | + let colorChange = [] | |
| 170 | + for (let i = 1; i < 7; i += 2) { | |
| 171 | + colorChange.push(parseInt("0x" + color.slice(i, i + 2))) | |
| 172 | + } | |
| 173 | + if (!str) { | |
| 174 | + return colorChange | |
| 175 | + } else { | |
| 176 | + return `rgb(${colorChange[0]}, ${colorChange[1]}, ${colorChange[2]})` | |
| 177 | + } | |
| 178 | + } else if (/^(rgb|RGB)/.test(color)) { | |
| 179 | + let arr = color.replace(/(?:\(|\)|rgb|RGB)*/g, "").split(',') | |
| 180 | + return arr.map(item => Number(item)) | |
| 181 | + } else { | |
| 182 | + return color | |
| 183 | + } | |
| 184 | +} | |
| 185 | + | |
| 186 | +/** | |
| 187 | + * 将rgb的颜色表示方式转换成hex表示方式 | |
| 188 | + * | |
| 189 | + * @param {Object} rgb rgb颜色值 | |
| 190 | + */ | |
| 191 | +function rgbToHex(rgb) { | |
| 192 | + let reg = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/ | |
| 193 | + if (/^(rgb|RGB)/.test(rgb)) { | |
| 194 | + let color = rgb.replace(/(?:\(|\)|rgb|GRB)*/g, "").split(',') | |
| 195 | + let strHex = '#' | |
| 196 | + for (let i = 0; i < color.length; i++) { | |
| 197 | + let hex = Number(color[i]).toString(16) | |
| 198 | + // 保证每个值否是两位数 | |
| 199 | + hex = String(hex).length === 1 ? 0 + '' + hex: hex | |
| 200 | + if (hex === '0') { | |
| 201 | + hex += hex | |
| 202 | + } | |
| 203 | + strHex += hex | |
| 204 | + } | |
| 205 | + if (strHex.length !== 7) { | |
| 206 | + strHex = rgb | |
| 207 | + } | |
| 208 | + return strHex | |
| 209 | + } else if (reg.test(rgb)) { | |
| 210 | + let num = rgb.replace(/#/, '').split('') | |
| 211 | + if (num.length === 6) { | |
| 212 | + return rgb | |
| 213 | + } else if (num.length === 3) { | |
| 214 | + let numHex = '#' | |
| 215 | + for (let i = 0; i < num.length; i++) { | |
| 216 | + numHex += (num[i] + num[i]) | |
| 217 | + } | |
| 218 | + return numHex | |
| 219 | + } | |
| 220 | + } else { | |
| 221 | + return rgb | |
| 222 | + } | |
| 223 | +} | |
| 224 | + | |
| 225 | +/** | |
| 226 | + * 将传入的颜色值转换为rgba字符串 | |
| 227 | + * | |
| 228 | + * @param {String} color 颜色 | |
| 229 | + * @param {Number} alpha 透明度 | |
| 230 | + */ | |
| 231 | +function colorToRGBA(color, alpha = 0.3) { | |
| 232 | + color = rgbToHex(color) | |
| 233 | + // 十六进制颜色值的正则表达式 | |
| 234 | + let reg = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/ | |
| 235 | + | |
| 236 | + color = color.toLowerCase() | |
| 237 | + if (color && reg.test(color)) { | |
| 238 | + // #000 => #000000 | |
| 239 | + if (color.length === 4) { | |
| 240 | + let colorNew = '#' | |
| 241 | + for (let i = 1; i < 4; i++) { | |
| 242 | + colorNew += color.slice(i, i + 1).concat(color.slice(i, i + 1)) | |
| 243 | + } | |
| 244 | + color = colorNew | |
| 245 | + } | |
| 246 | + // 处理六位的颜色值 | |
| 247 | + let colorChange = [] | |
| 248 | + for (let i = 1; i < 7; i += 2) { | |
| 249 | + colorChange.push(parseInt("0x" + color.slice(i, i + 2))) | |
| 250 | + } | |
| 251 | + return `rgba(${colorChange[0]}, ${colorChange[1]}, ${colorChange[2]}, ${alpha})` | |
| 252 | + } else { | |
| 253 | + return color | |
| 254 | + } | |
| 255 | +} | |
| 256 | + | |
| 257 | +export default { | |
| 258 | + COOL_BG_COLOR_COUNT: COOL_BG_COLOR_COUNT, | |
| 259 | + getTuniaoColorList, | |
| 260 | + getRandomColorClass, | |
| 261 | + getRandomCoolBgClass, | |
| 262 | + getBackgroundColorInternalClass, | |
| 263 | + getBackgroundColorStyle, | |
| 264 | + getFontColorInternalClass, | |
| 265 | + getFontColorStyle, | |
| 266 | + colorGradient, | |
| 267 | + hexToRGB, | |
| 268 | + rgbToHex, | |
| 269 | + colorToRGBA | |
| 270 | +} | ... | ... |
| 1 | +<template> | |
| 2 | + <view | |
| 3 | + v-if="visibleSync" | |
| 4 | + class="tn-popup-class tn-popup" | |
| 5 | + :style="[customStyle, popupStyle, { zIndex: elZIndex - 1}]" | |
| 6 | + hover-stop-propagation | |
| 7 | + > | |
| 8 | + <!-- mask --> | |
| 9 | + <view | |
| 10 | + class="tn-popup__mask" | |
| 11 | + :class="[{'tn-popup__mask--show': showPopup && mask}]" | |
| 12 | + :style="{zIndex: elZIndex - 2}" | |
| 13 | + @tap="maskClick" | |
| 14 | + @touchmove.stop.prevent = "() => {}" | |
| 15 | + hover-stop-propagation | |
| 16 | + ></view> | |
| 17 | + <!-- 弹框内容 --> | |
| 18 | + <view | |
| 19 | + class="tn-popup__content" | |
| 20 | + :class="[ | |
| 21 | + mode !== 'center' ? backgroundColorClass : '', | |
| 22 | + safeAreaInsetBottom ? 'tn-safe-area-inset-bottom' : '', | |
| 23 | + 'tn-popup--' + mode, | |
| 24 | + showPopup ? 'tn-popup__content--visible' : '', | |
| 25 | + zoom && mode === 'center' ? 'tn-popup__content__center--animation-zoom' : '' | |
| 26 | + ]" | |
| 27 | + :style="[contentStyle]" | |
| 28 | + @tap="modeCenterClose" | |
| 29 | + @touchmove.stop.prevent | |
| 30 | + @tap.stop.prevent | |
| 31 | + > | |
| 32 | + <!-- 居中时候的内容 --> | |
| 33 | + <view | |
| 34 | + v-if="mode === 'center'" | |
| 35 | + class="tn-popup__content__center_box" | |
| 36 | + :class="[backgroundColorClass]" | |
| 37 | + :style="[centerStyle]" | |
| 38 | + @touchmove.stop.prevent | |
| 39 | + @tap.stop.prevent | |
| 40 | + > | |
| 41 | + <!-- 关闭按钮 --> | |
| 42 | + <view | |
| 43 | + v-if="closeBtn" | |
| 44 | + class="tn-popup__close" | |
| 45 | + :class="[`tn-icon-${closeBtnIcon}`, `tn-popup__close--${closeBtnPosition}`]" | |
| 46 | + :style="[closeBtnStyle, {zIndex: elZIndex}]" | |
| 47 | + @tap="close" | |
| 48 | + ></view> | |
| 49 | + <scroll-view scroll-y class="tn-popup__content__scroll-view"> | |
| 50 | + <slot></slot> | |
| 51 | + </scroll-view> | |
| 52 | + </view> | |
| 53 | + | |
| 54 | + <!-- 除居中外的其他情况 --> | |
| 55 | + <scroll-view scroll-y v-else class="tn-popup__content__scroll-view"> | |
| 56 | + <slot></slot> | |
| 57 | + </scroll-view> | |
| 58 | + <!-- 关闭按钮 --> | |
| 59 | + <view | |
| 60 | + v-if="mode !== 'center' && closeBtn" | |
| 61 | + class="tn-popup__close" | |
| 62 | + :class="[`tn-popup__close--${closeBtnPosition}`]" | |
| 63 | + :style="{zIndex: elZIndex}" | |
| 64 | + @tap="close" | |
| 65 | + > | |
| 66 | + <view :class="[`tn-icon-${closeBtnIcon}`]" :style="[closeBtnStyle]"></view> | |
| 67 | + </view> | |
| 68 | + </view> | |
| 69 | + </view> | |
| 70 | +</template> | |
| 71 | + | |
| 72 | +<script> | |
| 73 | + import componentsColorMixin from '../../components_color.js' | |
| 74 | + // 格式化字符串工具 | |
| 75 | + import string from '../../string.js' | |
| 76 | + export default { | |
| 77 | + mixins: [componentsColorMixin], | |
| 78 | + name: 'tn-popup', | |
| 79 | + props: { | |
| 80 | + value: { | |
| 81 | + type: Boolean, | |
| 82 | + default: false | |
| 83 | + }, | |
| 84 | + // 弹出方向 | |
| 85 | + // left/right/top/bottom/center | |
| 86 | + mode: { | |
| 87 | + type: String, | |
| 88 | + default: 'left' | |
| 89 | + }, | |
| 90 | + // 是否显示遮罩 | |
| 91 | + mask: { | |
| 92 | + type: Boolean, | |
| 93 | + default: true | |
| 94 | + }, | |
| 95 | + // 抽屉的宽度(mode=left/right),高度(mode=top/bottom) | |
| 96 | + length: { | |
| 97 | + type: [Number, String], | |
| 98 | + default: 'auto' | |
| 99 | + }, | |
| 100 | + // 宽度,只对左,右,中部弹出时起作用,单位rpx,或者"auto" | |
| 101 | + // 或者百分比"50%",表示由内容撑开高度或者宽度,优先级高于length参数 | |
| 102 | + width: { | |
| 103 | + type: String, | |
| 104 | + default: '' | |
| 105 | + }, | |
| 106 | + // 高度,只对上,下,中部弹出时起作用,单位rpx,或者"auto" | |
| 107 | + // 或者百分比"50%",表示由内容撑开高度或者宽度,优先级高于length参数 | |
| 108 | + height: { | |
| 109 | + type: String, | |
| 110 | + default: '' | |
| 111 | + }, | |
| 112 | + // 是否开启动画,只在mode=center有效 | |
| 113 | + zoom: { | |
| 114 | + type: Boolean, | |
| 115 | + default: true | |
| 116 | + }, | |
| 117 | + // 是否开启底部安全区适配,开启的话,会在iPhoneX机型底部添加一定的内边距 | |
| 118 | + safeAreaInsetBottom: { | |
| 119 | + type: Boolean, | |
| 120 | + default: false | |
| 121 | + }, | |
| 122 | + // 是否可以通过点击遮罩进行关闭 | |
| 123 | + maskCloseable: { | |
| 124 | + type: Boolean, | |
| 125 | + default: true | |
| 126 | + }, | |
| 127 | + // 用户自定义样式 | |
| 128 | + customStyle: { | |
| 129 | + type: Object, | |
| 130 | + default() { | |
| 131 | + return {} | |
| 132 | + } | |
| 133 | + }, | |
| 134 | + // 显示圆角的大小 | |
| 135 | + borderRadius: { | |
| 136 | + type: Number, | |
| 137 | + default: 0 | |
| 138 | + }, | |
| 139 | + // zIndex | |
| 140 | + zIndex: { | |
| 141 | + type: Number, | |
| 142 | + default: 0 | |
| 143 | + }, | |
| 144 | + // 是否显示关闭按钮 | |
| 145 | + closeBtn: { | |
| 146 | + type: Boolean, | |
| 147 | + default: false | |
| 148 | + }, | |
| 149 | + // 关闭按钮的图标 | |
| 150 | + closeBtnIcon: { | |
| 151 | + type: String, | |
| 152 | + default: 'close' | |
| 153 | + }, | |
| 154 | + // 关闭按钮显示的位置 | |
| 155 | + // top-left/top-right/bottom-left/bottom-right | |
| 156 | + closeBtnPosition: { | |
| 157 | + type: String, | |
| 158 | + default: 'top-right' | |
| 159 | + }, | |
| 160 | + // 关闭按钮图标颜色 | |
| 161 | + closeIconColor: { | |
| 162 | + type: String, | |
| 163 | + default: '#AAAAAA' | |
| 164 | + }, | |
| 165 | + // 关闭按钮图标的大小 | |
| 166 | + closeIconSize: { | |
| 167 | + type: Number, | |
| 168 | + default: 30 | |
| 169 | + }, | |
| 170 | + // 给一个负的margin-top,往上偏移,避免和键盘重合的情况,仅在mode=center时有效 | |
| 171 | + negativeTop: { | |
| 172 | + type: Number, | |
| 173 | + default: 0 | |
| 174 | + }, | |
| 175 | + // marginTop,在mode = top,left,right时生效,避免用户使用了自定义导航栏,组件把导航栏遮挡了 | |
| 176 | + marginTop: { | |
| 177 | + type: Number, | |
| 178 | + default: 0 | |
| 179 | + }, | |
| 180 | + // 此为内部参数,不在文档对外使用,为了解决Picker和keyboard等融合了弹窗的组件 | |
| 181 | + // 对v-model双向绑定多层调用造成报错不能修改props值的问题 | |
| 182 | + popup: { | |
| 183 | + type: Boolean, | |
| 184 | + default: true | |
| 185 | + }, | |
| 186 | + }, | |
| 187 | + computed: { | |
| 188 | + // 处理使用了自定义导航栏时被遮挡的问题 | |
| 189 | + popupStyle() { | |
| 190 | + let style = {} | |
| 191 | + if ((this.mode === 'top' || this.mode === 'left' || this.mode === 'right') && this.marginTop) { | |
| 192 | + style.marginTop = string.getLengthUnitValue(this.marginTop, 'px') | |
| 193 | + } | |
| 194 | + | |
| 195 | + return style | |
| 196 | + }, | |
| 197 | + // 根据mode的位置,设定其弹窗的宽度(mode = left|right),或者高度(mode = top|bottom) | |
| 198 | + contentStyle() { | |
| 199 | + let style = {} | |
| 200 | + // 如果是左边或者上边弹出时,需要给translate设置为负值,用于隐藏 | |
| 201 | + if (this.mode === 'left' || this.mode === 'right') { | |
| 202 | + style = { | |
| 203 | + width: this.width ? string.getLengthUnitValue(this.width) : string.getLengthUnitValue(this.length), | |
| 204 | + height: '100%', | |
| 205 | + transform: `translate3D(${this.mode === 'left' ? '-100%' : '100%'}, 0px, 0px)` | |
| 206 | + } | |
| 207 | + } else if (this.mode === 'top' || this.mode === 'bottom') { | |
| 208 | + style = { | |
| 209 | + width: '100%', | |
| 210 | + height: this.height ? string.getLengthUnitValue(this.height) : string.getLengthUnitValue(this.length), | |
| 211 | + transform: `translate3D(0px, ${this.mode === 'top' ? '-100%': '100%'}, 0px)` | |
| 212 | + } | |
| 213 | + } | |
| 214 | + style.zIndex = this.elZIndex | |
| 215 | + // 如果设置了圆角的值,添加弹窗的圆角 | |
| 216 | + if (this.borderRadius) { | |
| 217 | + switch(this.mode) { | |
| 218 | + case 'left': | |
| 219 | + style.borderRadius = `0 ${this.borderRadius}rpx ${this.borderRadius}rpx 0` | |
| 220 | + break | |
| 221 | + case 'top': | |
| 222 | + style.borderRadius = `0 0 ${this.borderRadius}rpx ${this.borderRadius}rpx` | |
| 223 | + break | |
| 224 | + case 'right': | |
| 225 | + style.borderRadius = `${this.borderRadius}rpx 0 0 ${this.borderRadius}rpx` | |
| 226 | + break | |
| 227 | + case 'bottom': | |
| 228 | + style.borderRadius = `${this.borderRadius}rpx ${this.borderRadius}rpx 0 0` | |
| 229 | + break | |
| 230 | + } | |
| 231 | + style.overflow = 'hidden' | |
| 232 | + } | |
| 233 | + | |
| 234 | + if (this.backgroundColorStyle && this.mode !== 'center') { | |
| 235 | + style.backgroundColor = this.backgroundColorStyle | |
| 236 | + } | |
| 237 | + | |
| 238 | + return style | |
| 239 | + }, | |
| 240 | + // 中部弹窗的样式 | |
| 241 | + centerStyle() { | |
| 242 | + let style = {} | |
| 243 | + style.width = this.width ? string.getLengthUnitValue(this.width) : string.getLengthUnitValue(this.length) | |
| 244 | + // 中部弹出的模式,如果没有设置高度,就用auto值,由内容撑开 | |
| 245 | + style.height = this.height ? string.getLengthUnitValue(this.height) : 'auto' | |
| 246 | + style.zIndex = this.elZIndex | |
| 247 | + if (this.negativeTop) { | |
| 248 | + style.marginTop = `-${string.getLengthUnitValue(this.negativeTop)}` | |
| 249 | + } | |
| 250 | + if (this.borderRadius) { | |
| 251 | + style.borderRadius = `${this.borderRadius}rpx` | |
| 252 | + style.overflow='hidden' | |
| 253 | + } | |
| 254 | + if (this.backgroundColorStyle) { | |
| 255 | + style.backgroundColor = this.backgroundColorStyle | |
| 256 | + } | |
| 257 | + return style | |
| 258 | + }, | |
| 259 | + // 关闭按钮样式 | |
| 260 | + closeBtnStyle() { | |
| 261 | + let style = {} | |
| 262 | + if (this.closeIconColor) { | |
| 263 | + style.color = this.closeIconColor | |
| 264 | + } | |
| 265 | + if (this.closeIconSize) { | |
| 266 | + style.fontSize = this.closeIconSize + 'rpx' | |
| 267 | + } | |
| 268 | + | |
| 269 | + return style | |
| 270 | + }, | |
| 271 | + elZIndex() { | |
| 272 | + return this.zIndex ? this.zIndex : 20075 | |
| 273 | + } | |
| 274 | + }, | |
| 275 | + data() { | |
| 276 | + return { | |
| 277 | + timer: null, | |
| 278 | + visibleSync: false, | |
| 279 | + showPopup: false, | |
| 280 | + closeFromInner: false | |
| 281 | + } | |
| 282 | + }, | |
| 283 | + watch: { | |
| 284 | + value(val) { | |
| 285 | + if (val) { | |
| 286 | + // console.log(this.visibleSync); | |
| 287 | + if (this.visibleSync) { | |
| 288 | + this.visibleSync = false | |
| 289 | + return | |
| 290 | + } | |
| 291 | + this.open() | |
| 292 | + } else if (!this.closeFromInner) { | |
| 293 | + this.close() | |
| 294 | + } | |
| 295 | + this.closeFromInner = false | |
| 296 | + } | |
| 297 | + }, | |
| 298 | + mounted() { | |
| 299 | + // 组件渲染完成时,检查value是否为true,如果是,弹出popup | |
| 300 | + this.value && this.open() | |
| 301 | + }, | |
| 302 | + methods: { | |
| 303 | + // 点击遮罩 | |
| 304 | + maskClick() { | |
| 305 | + if (!this.maskCloseable) return | |
| 306 | + this.close() | |
| 307 | + }, | |
| 308 | + open() { | |
| 309 | + this.change('visibleSync', 'showPopup', true) | |
| 310 | + }, | |
| 311 | + // 关闭弹框 | |
| 312 | + close() { | |
| 313 | + // 标记关闭是内部发生的,否则修改了value值,导致watch中对value检测,导致再执行一遍close | |
| 314 | + // 造成@close事件触发两次 | |
| 315 | + this.closeFromInner = true | |
| 316 | + this.change('showPopup', 'visibleSync', false) | |
| 317 | + }, | |
| 318 | + // 中部弹出时,需要.tn-drawer-content将内容居中,此元素会铺满屏幕,点击需要关闭弹窗 | |
| 319 | + // 让其只在mode=center时起作用 | |
| 320 | + modeCenterClose() { | |
| 321 | + if (this.mode != 'center' || !this.maskCloseable) return | |
| 322 | + this.close() | |
| 323 | + }, | |
| 324 | + // 关闭时先通过动画隐藏弹窗和遮罩,再移除整个组件 | |
| 325 | + // 打开时,先渲染组件,延时一定时间再让遮罩和弹窗的动画起作用 | |
| 326 | + change(param1, param2, status) { | |
| 327 | + // 如果this.popup为false,意味着为picker,actionsheet等组件调用了popup组件 | |
| 328 | + if (this.popup === true) { | |
| 329 | + this.$emit('input', status) | |
| 330 | + } | |
| 331 | + this[param1] = status | |
| 332 | + if (status) { | |
| 333 | + // #ifdef H5 || MP | |
| 334 | + this.timer = setTimeout(() => { | |
| 335 | + this[param2] = status | |
| 336 | + this.$emit(status ? 'open' : 'close') | |
| 337 | + clearTimeout(this.timer) | |
| 338 | + }, 10) | |
| 339 | + // #endif | |
| 340 | + // #ifndef H5 || MP | |
| 341 | + this.$nextTick(() => { | |
| 342 | + this[param2] = status | |
| 343 | + this.$emit(status ? 'open' : 'close') | |
| 344 | + }) | |
| 345 | + // #endif | |
| 346 | + } else { | |
| 347 | + this.timer = setTimeout(() => { | |
| 348 | + this[param2] = status | |
| 349 | + this.$emit(status ? 'open' : 'close') | |
| 350 | + clearTimeout(this.timer) | |
| 351 | + }, 250) | |
| 352 | + } | |
| 353 | + } | |
| 354 | + } | |
| 355 | + } | |
| 356 | +</script> | |
| 357 | + | |
| 358 | +<style lang="scss" scoped> | |
| 359 | + @import '../../theme.scss'; | |
| 360 | + .tn-popup { | |
| 361 | + /* #ifndef APP-NVUE */ | |
| 362 | + display: block; | |
| 363 | + /* #endif */ | |
| 364 | + position: fixed; | |
| 365 | + top: 0; | |
| 366 | + left: 0; | |
| 367 | + right: 0; | |
| 368 | + bottom: 0; | |
| 369 | + overflow: hidden; | |
| 370 | + z-index: 29091 !important; | |
| 371 | + | |
| 372 | + &__content { | |
| 373 | + /* #ifndef APP-NVUE */ | |
| 374 | + display: block; | |
| 375 | + /* #endif */ | |
| 376 | + position: absolute; | |
| 377 | + transition: all 0.25s linear; | |
| 378 | + | |
| 379 | + &--visible { | |
| 380 | + transform: translate3D(0px, 0px, 0px) !important; | |
| 381 | + &.tn-popup--center { | |
| 382 | + transform: scale(1); | |
| 383 | + opacity: 1; | |
| 384 | + } | |
| 385 | + } | |
| 386 | + | |
| 387 | + &__center_box { | |
| 388 | + min-width: 100rpx; | |
| 389 | + min-height: 100rpx; | |
| 390 | + /* #ifndef APP-NVUE */ | |
| 391 | + display: block; | |
| 392 | + /* #endif */ | |
| 393 | + position: relative; | |
| 394 | + background-color: #FFFFFF; | |
| 395 | + } | |
| 396 | + | |
| 397 | + &__scroll-view { | |
| 398 | + width: 100%; | |
| 399 | + height: 100%; | |
| 400 | + } | |
| 401 | + | |
| 402 | + &__center--animation-zoom { | |
| 403 | + transform: scale(1.15); | |
| 404 | + } | |
| 405 | + } | |
| 406 | + | |
| 407 | + &__scroll_view { | |
| 408 | + width: 100%; | |
| 409 | + height: 100%; | |
| 410 | + } | |
| 411 | + | |
| 412 | + &--left { | |
| 413 | + top: 0; | |
| 414 | + bottom: 0; | |
| 415 | + left: 0; | |
| 416 | + background-color: #FFFFFF; | |
| 417 | + } | |
| 418 | + | |
| 419 | + &--right { | |
| 420 | + top: 0; | |
| 421 | + bottom: 0; | |
| 422 | + right: 0; | |
| 423 | + background-color: #FFFFFF; | |
| 424 | + } | |
| 425 | + | |
| 426 | + &--top { | |
| 427 | + left: 0; | |
| 428 | + right: 0; | |
| 429 | + top: 0; | |
| 430 | + background-color: #FFFFFF; | |
| 431 | + } | |
| 432 | + | |
| 433 | + &--bottom { | |
| 434 | + left: 0; | |
| 435 | + right: 0; | |
| 436 | + bottom: 0; | |
| 437 | + background-color: #FFFFFF; | |
| 438 | + } | |
| 439 | + | |
| 440 | + &--center { | |
| 441 | + display: flex; | |
| 442 | + flex-direction: column; | |
| 443 | + bottom: 0; | |
| 444 | + top: 0; | |
| 445 | + left: 0; | |
| 446 | + right: 0; | |
| 447 | + justify-content: center; | |
| 448 | + align-items: center; | |
| 449 | + opacity: 0; | |
| 450 | + } | |
| 451 | + | |
| 452 | + &__close { | |
| 453 | + position: absolute; | |
| 454 | + | |
| 455 | + &--top-left { | |
| 456 | + top: 30rpx; | |
| 457 | + left: 30rpx; | |
| 458 | + } | |
| 459 | + | |
| 460 | + &--top-right { | |
| 461 | + top: 30rpx; | |
| 462 | + right: 30rpx; | |
| 463 | + } | |
| 464 | + | |
| 465 | + &--bottom-left { | |
| 466 | + bottom: 30rpx; | |
| 467 | + left: 30rpx; | |
| 468 | + } | |
| 469 | + | |
| 470 | + &--bottom-right { | |
| 471 | + bottom: 30rpx; | |
| 472 | + right: 30rpx; | |
| 473 | + } | |
| 474 | + } | |
| 475 | + | |
| 476 | + &__mask { | |
| 477 | + width: 100%; | |
| 478 | + height: 100%; | |
| 479 | + position: fixed; | |
| 480 | + top: 0; | |
| 481 | + left: 0; | |
| 482 | + right: 0; | |
| 483 | + border: 0; | |
| 484 | + background-color: $tn-mask-bg-color; | |
| 485 | + transition: 0.25s linear; | |
| 486 | + transition-property: opacity; | |
| 487 | + opacity: 0; | |
| 488 | + | |
| 489 | + &--show { | |
| 490 | + opacity: 1; | |
| 491 | + } | |
| 492 | + } | |
| 493 | + } | |
| 494 | +</style> | ... | ... |
uni_modules/tn-popup/components_color.js
0 → 100644
| 1 | +// 格式化字符串工具 | |
| 2 | +import string from './string.js' | |
| 3 | +// 获取颜色工具 | |
| 4 | +import color from './color.js' | |
| 5 | +module.exports = { | |
| 6 | + data() { | |
| 7 | + | |
| 8 | + }, | |
| 9 | + props: { | |
| 10 | + // 背景颜色 | |
| 11 | + backgroundColor: { | |
| 12 | + type: String, | |
| 13 | + default: '' | |
| 14 | + }, | |
| 15 | + // 字体颜色 | |
| 16 | + fontColor: { | |
| 17 | + type: String, | |
| 18 | + default: '' | |
| 19 | + }, | |
| 20 | + // 字体大小 | |
| 21 | + fontSize: { | |
| 22 | + type: Number, | |
| 23 | + default: 0 | |
| 24 | + }, | |
| 25 | + // 字体大小单位 | |
| 26 | + fontUnit: { | |
| 27 | + type: String, | |
| 28 | + default: 'rpx' | |
| 29 | + } | |
| 30 | + }, | |
| 31 | + computed: { | |
| 32 | + backgroundColorStyle() { | |
| 33 | + return color.getBackgroundColorStyle(this.backgroundColor) | |
| 34 | + }, | |
| 35 | + backgroundColorClass() { | |
| 36 | + return color.getBackgroundColorInternalClass(this.backgroundColor) | |
| 37 | + }, | |
| 38 | + fontColorStyle() { | |
| 39 | + return color.getFontColorStyle(this.fontColor) | |
| 40 | + }, | |
| 41 | + fontColorClass() { | |
| 42 | + return color.getFontColorInternalClass(this.fontColor) | |
| 43 | + }, | |
| 44 | + fontSizeStyle() { | |
| 45 | + string.getLengthUnitValue(this.fontSize, this.fontUnit) | |
| 46 | + } | |
| 47 | + }, | |
| 48 | + methods: { | |
| 49 | + | |
| 50 | + } | |
| 51 | +} | |
| \ No newline at end of file | ... | ... |
uni_modules/tn-popup/package.json
0 → 100644
| 1 | +{ | |
| 2 | + "id": "tn-popup", | |
| 3 | + "displayName": "tn-popup 弹出层 全面兼容vue2、app、h5、wx小程序", | |
| 4 | + "version": "1.0.0", | |
| 5 | + "description": "弹出层容器,用于展示弹窗、信息提示等内容,支持上、下、左、右和中部弹出。组件只提供容器,内部内容由用户自定义", | |
| 6 | + "keywords": [ | |
| 7 | + "tuniaoui", | |
| 8 | + "tuniao", | |
| 9 | + "tn-popup", | |
| 10 | + "popup", | |
| 11 | + "弹出层" | |
| 12 | +], | |
| 13 | + "repository": "", | |
| 14 | + "engines": { | |
| 15 | + "HBuilderX": "^3.1.0" | |
| 16 | + }, | |
| 17 | + "dcloudext": { | |
| 18 | + "type": "component-vue", | |
| 19 | + "sale": { | |
| 20 | + "regular": { | |
| 21 | + "price": "0.00" | |
| 22 | + }, | |
| 23 | + "sourcecode": { | |
| 24 | + "price": "0.00" | |
| 25 | + } | |
| 26 | + }, | |
| 27 | + "contact": { | |
| 28 | + "qq": "" | |
| 29 | + }, | |
| 30 | + "declaration": { | |
| 31 | + "ads": "无", | |
| 32 | + "data": "无", | |
| 33 | + "permissions": "无" | |
| 34 | + }, | |
| 35 | + "npmurl": "" | |
| 36 | + }, | |
| 37 | + "uni_modules": { | |
| 38 | + "dependencies": [], | |
| 39 | + "encrypt": [], | |
| 40 | + "platforms": { | |
| 41 | + "cloud": { | |
| 42 | + "tcb": "y", | |
| 43 | + "aliyun": "y", | |
| 44 | + "alipay": "y" | |
| 45 | + }, | |
| 46 | + "client": { | |
| 47 | + "Vue": { | |
| 48 | + "vue2": "y", | |
| 49 | + "vue3": "u" | |
| 50 | + }, | |
| 51 | + "App": { | |
| 52 | + "app-vue": "y", | |
| 53 | + "app-nvue": "u", | |
| 54 | + "app-uvue": "u" | |
| 55 | + }, | |
| 56 | + "H5-mobile": { | |
| 57 | + "Safari": "y", | |
| 58 | + "Android Browser": "y", | |
| 59 | + "微信浏览器(Android)": "y", | |
| 60 | + "QQ浏览器(Android)": "y" | |
| 61 | + }, | |
| 62 | + "H5-pc": { | |
| 63 | + "Chrome": "y", | |
| 64 | + "IE": "y", | |
| 65 | + "Edge": "y", | |
| 66 | + "Firefox": "y", | |
| 67 | + "Safari": "y" | |
| 68 | + }, | |
| 69 | + "小程序": { | |
| 70 | + "微信": "y", | |
| 71 | + "阿里": "u", | |
| 72 | + "百度": "u", | |
| 73 | + "字节跳动": "u", | |
| 74 | + "QQ": "u", | |
| 75 | + "钉钉": "u", | |
| 76 | + "快手": "u", | |
| 77 | + "飞书": "u", | |
| 78 | + "京东": "u" | |
| 79 | + }, | |
| 80 | + "快应用": { | |
| 81 | + "华为": "u", | |
| 82 | + "联盟": "u" | |
| 83 | + } | |
| 84 | + } | |
| 85 | + } | |
| 86 | + } | |
| 87 | +} | |
| \ No newline at end of file | ... | ... |
uni_modules/tn-popup/readme.md
0 → 100644
| 1 | +# Popup 弹出层 | |
| 2 | +> 组件名: tn-popup | |
| 3 | +> 弹出层容器,用于展示弹窗、信息提示等内容,支持上、下、左、右和中部弹出。组件只提供容器,内部内容由用户自定义。 | |
| 4 | +# 提示 | |
| 5 | +> popup弹出层中对应自定义内容的容器中已经内置了scroll-view元素,内如内容超出容器的高度,将会自动获得垂直滚动的特性,如果您因为在slot内容做了滚动的处理,而造成了 冲突的话,请移除自定义关于滚动部分的逻辑。 | |
| 6 | +# [查看文档](https://vue2.tuniaokj.com/components/popup.html) | |
| 7 | +## [下载完整示例项目](https://ext.dcloud.net.cn/plugin?name=tuniao-tuniaoui) | |
| 8 | +## [问题反馈/提出建议](https://vue2.tuniaokj.com/cooperation/about.html) | |
| 9 | + | |
| \ No newline at end of file | ... | ... |
uni_modules/tn-popup/string.js
0 → 100644
| 1 | +/** | |
| 2 | + * 去掉字符串中空格 | |
| 3 | + * | |
| 4 | + * @param {String} str 待处理的字符串 | |
| 5 | + * @param {String} type 处理类型 | |
| 6 | + */ | |
| 7 | +function trim(str, type = 'both') { | |
| 8 | + if (type === 'both') { | |
| 9 | + return str.replace(/^\s+|\s+$/g, "") | |
| 10 | + } else if (type === 'left') { | |
| 11 | + return str.replace(/^\s*/g, "") | |
| 12 | + } else if (type === 'right') { | |
| 13 | + return str.replace(/(\s*$)/g, "") | |
| 14 | + } else if (type === 'all') { | |
| 15 | + return str.replace(/\s+/g, "") | |
| 16 | + } else { | |
| 17 | + return str | |
| 18 | + } | |
| 19 | +} | |
| 20 | + | |
| 21 | +/** | |
| 22 | + * 获取带单位的长度值 | |
| 23 | + * | |
| 24 | + * @param {String} value 待处理的值 | |
| 25 | + * @param {String} unit 单位 | |
| 26 | + */ | |
| 27 | +function getLengthUnitValue(value, unit = 'rpx') { | |
| 28 | + if (!value) { | |
| 29 | + return '' | |
| 30 | + } | |
| 31 | + if (/(%|px|rpx|auto)$/.test(value)) return value | |
| 32 | + else return value + unit | |
| 33 | +} | |
| 34 | + | |
| 35 | +/** | |
| 36 | + * 将驼峰命名的字符串转换为指定连接符来进行连接 | |
| 37 | + * | |
| 38 | + * @param {Object} string 待转换的字符串 | |
| 39 | + * @param {Object} replace 进行连接的字符 | |
| 40 | + */ | |
| 41 | +function humpConvertChar(string, replace = '_') { | |
| 42 | + if (!string || !replace) { | |
| 43 | + return '' | |
| 44 | + } | |
| 45 | + return string.replace(/([A-Z])/g, `${replace}$1`).toLowerCase() | |
| 46 | +} | |
| 47 | + | |
| 48 | +/** | |
| 49 | + * 将用指定连接符来进行连接的字符串转为驼峰命名的字符串 | |
| 50 | + * | |
| 51 | + * @param {Object} string 待转换的字符串 | |
| 52 | + * @param {Object} replace 进行连接的字符 | |
| 53 | + */ | |
| 54 | +function charConvertHump(string, replace = '_') { | |
| 55 | + if (!string || !replace) { | |
| 56 | + return '' | |
| 57 | + } | |
| 58 | + let reg = RegExp(replace + "(\\w)", "g") | |
| 59 | + return string.replace(reg, function(all, letter) { | |
| 60 | + return letter.toUpperCase() | |
| 61 | + }) | |
| 62 | +} | |
| 63 | + | |
| 64 | +export default { | |
| 65 | + trim, | |
| 66 | + getLengthUnitValue, | |
| 67 | + humpConvertChar, | |
| 68 | + charConvertHump | |
| 69 | +} | |
| \ No newline at end of file | ... | ... |
uni_modules/tn-popup/theme.scss
0 → 100644
| 1 | +// 此文件为TuniaoUI的主题变量,这些变量目前只能通过uni.scss引入才有效,另外由于 | |
| 2 | +// uni.scss中引入的样式会同时混入到全局样式文件和单独每一个页面的样式中,造成微信程序包太大, | |
| 3 | +// 故uni.scss只建议放scss变量名相关样式,其他的样式可以通过main.js或者App.vue引入 | |
| 4 | + | |
| 5 | +// 组件配置 | |
| 6 | +$tn-form-item-height: 70rpx; | |
| 7 | + | |
| 8 | + | |
| 9 | +// 主颜色 | |
| 10 | +$tn-main-color: #01BEFF; | |
| 11 | +$tn-main-orange: #FBBD12; | |
| 12 | +$tn-embellished-green: #00FFC6; | |
| 13 | +$tn-embellished-yellow: #FFF00D; | |
| 14 | +$tn-auxiliary-powder: #FF71D2; | |
| 15 | +$tn-auxiliary-blue: #82B2FF; | |
| 16 | +$tn-bg-color: #FFFFFF; | |
| 17 | +$tn-bg-gray-color: #F4F4F4; | |
| 18 | +$tn-space-color: #F8F7F8; | |
| 19 | + | |
| 20 | +// 边框颜色 | |
| 21 | +$tn-border-solid-color: rgba(0, 0, 0, 0.1); | |
| 22 | +$tn-border-solids-color: #eee; | |
| 23 | +$tn-border-dashed-color: #ddd; | |
| 24 | + | |
| 25 | +// 阴影颜色 | |
| 26 | +$tn-shadow-color: rgba(0, 0, 0, 0.1); | |
| 27 | +$tn-box-shadow-color: rgba(0, 0, 0, 0.2); | |
| 28 | + | |
| 29 | +// 字体颜色 | |
| 30 | +$tn-font-color: #080808; | |
| 31 | +$tn-font-sub-color: #AAAAAA; | |
| 32 | +$tn-content-color: #838383; | |
| 33 | +$tn-font-holder-color: #E6E6E6; | |
| 34 | + | |
| 35 | +$tn-mask-bg-color: rgba(0, 0, 0, 0.4); | |
| 36 | + | |
| 37 | +$tn-progress-bg-color: #f0f0f0; | |
| 38 | + | |
| 39 | + | |
| 40 | +$tn-color-red: #E83A30; | |
| 41 | +$tn-color-red-dark: #BA2E26; | |
| 42 | +$tn-color-red-disabled: #F39C97; | |
| 43 | +$tn-color-red-light: #FAD8D6; | |
| 44 | + | |
| 45 | +$tn-color-purplered: #E72F8C; | |
| 46 | +$tn-color-purplered-dark: #B9266F; | |
| 47 | +$tn-color-purplered-disabled: #F397C5; | |
| 48 | +$tn-color-purplered-light: #FAD5E8; | |
| 49 | + | |
| 50 | +$tn-color-purple: #892FE8; | |
| 51 | +$tn-color-purple-dark: #6E26BA; | |
| 52 | +$tn-color-purple-disabled: #C497F3; | |
| 53 | +$tn-color-purple-light: #E7D5FA; | |
| 54 | + | |
| 55 | +$tn-color-bluepurple: #5F4FD9; | |
| 56 | +$tn-color-bluepurple-dark: #4C3FAE; | |
| 57 | +$tn-color-bluepurple-disabled: #AFA7EC; | |
| 58 | +$tn-color-bluepurple-light: #DFDCF7; | |
| 59 | + | |
| 60 | +$tn-color-aquablue: #3646FF; | |
| 61 | +$tn-color-aquablue-dark: #2B38CC; | |
| 62 | +$tn-color-aquablue-disabled: #9AA2FF; | |
| 63 | +$tn-color-aquablue-light: #D7DAFF; | |
| 64 | + | |
| 65 | +$tn-color-blue: #3D7EFF; | |
| 66 | +$tn-color-blue-dark: #3165CC; | |
| 67 | +$tn-color-blue-disabled: #9EBEFF; | |
| 68 | +$tn-color-blue-light: #D8E5FF; | |
| 69 | + | |
| 70 | +$tn-color-indigo: #31C9E8; | |
| 71 | +$tn-color-indigo-dark: #27A1BA; | |
| 72 | +$tn-color-indigo-disabled: #98E4F3; | |
| 73 | +$tn-color-indigo-light: #D6F4FA; | |
| 74 | + | |
| 75 | +$tn-color-cyan: #2DE8BD; | |
| 76 | +$tn-color-cyan-dark: #24BA97; | |
| 77 | +$tn-color-cyan-disabled: #96F3DE; | |
| 78 | +$tn-color-cyan-light: #D5FAF2; | |
| 79 | + | |
| 80 | +$tn-color-teal: #24F083; | |
| 81 | +$tn-color-teal-dark: #1DC069; | |
| 82 | +$tn-color-teal-disabled: #91F7C1; | |
| 83 | +$tn-color-teal-light: #D3FCE6; | |
| 84 | + | |
| 85 | +$tn-color-green: #31E749; | |
| 86 | +$tn-color-green-dark: #27B93A; | |
| 87 | +$tn-color-green-disabled: #98F3A4; | |
| 88 | +$tn-color-green-light: #D6FADB; | |
| 89 | + | |
| 90 | +$tn-color-yellowgreen: #A4E82F; | |
| 91 | +$tn-color-yellowgreen-dark: #82BA26; | |
| 92 | +$tn-color-yellowgreen-disabled: #D1F397; | |
| 93 | +$tn-color-yellowgreen-light: #EDFAD5; | |
| 94 | + | |
| 95 | +$tn-color-lime: #D5EB00; | |
| 96 | +$tn-color-lime-dark: #AABC00; | |
| 97 | +$tn-color-lime-disabled: #E9F57F; | |
| 98 | +$tn-color-lime-light: #F7FBCC; | |
| 99 | + | |
| 100 | +$tn-color-yellow: #FFF420; | |
| 101 | +$tn-color-yellow-dark: #CCC21A; | |
| 102 | +$tn-color-yellow-disabled: #FFF88F; | |
| 103 | +$tn-color-yellow-light: #FFFDD2; | |
| 104 | + | |
| 105 | +$tn-color-orangeyellow: #FFCA28; | |
| 106 | +$tn-color-orangeyellow-dark: #CCA220; | |
| 107 | +$tn-color-orangeyellow-disabled: #FFE493; | |
| 108 | +$tn-color-orangeyellow-light: #FFF4D4; | |
| 109 | + | |
| 110 | +$tn-color-orange: #FFA726; | |
| 111 | +$tn-color-orange-dark: #CC851E; | |
| 112 | +$tn-color-orange-disabled: #FFD392; | |
| 113 | +$tn-color-orange-light: #FFEDD4 ; | |
| 114 | + | |
| 115 | +$tn-color-orangered: #FF7043; | |
| 116 | +$tn-color-orangered-dark: #CC5A36; | |
| 117 | +$tn-color-orangered-disabled: #FFB7A1; | |
| 118 | +$tn-color-orangered-light: #FFE2D9; | |
| 119 | + | |
| 120 | +$tn-color-brown: #914F2C; | |
| 121 | +$tn-color-brown-dark: #743F23; | |
| 122 | +$tn-color-brown-disabled: #C8A795; | |
| 123 | +$tn-color-brown-light: #E9DCD5; | |
| 124 | + | |
| 125 | +$tn-color-grey: #78909C; | |
| 126 | +$tn-color-grey-dark: #5F7E8B; | |
| 127 | +$tn-color-grey-disabled: #C6D1D8; | |
| 128 | +$tn-color-grey-light: #E4E9EC; | |
| 129 | + | |
| 130 | +$tn-color-gray: #AAAAAA; | |
| 131 | +$tn-color-gray-dark: #838383; | |
| 132 | +$tn-color-gray-disabled: #E6E6E6; | |
| 133 | +$tn-color-gray-light: #F8F7F8; | |
| 134 | + | |
| 135 | +$tn-cool-bg-color-1-start: #F5317F; | |
| 136 | +$tn-cool-bg-color-1-end: #FF7C6E; | |
| 137 | + | |
| 138 | +$tn-cool-bg-color-2-start: #CA26FF; | |
| 139 | +$tn-cool-bg-color-2-end: #F360A7; | |
| 140 | + | |
| 141 | +$tn-cool-bg-color-3-start: #A26FFC; | |
| 142 | +$tn-cool-bg-color-3-end: #9D12FF; | |
| 143 | + | |
| 144 | +$tn-cool-bg-color-4-start: #AA77F0; | |
| 145 | +$tn-cool-bg-color-4-end: #E871E5; | |
| 146 | + | |
| 147 | +$tn-cool-bg-color-5-start: #40A0F7; | |
| 148 | +$tn-cool-bg-color-5-end: #4866E6; | |
| 149 | + | |
| 150 | +$tn-cool-bg-color-6-start: #209CFF; | |
| 151 | +$tn-cool-bg-color-6-end: #68E0CF; | |
| 152 | + | |
| 153 | +$tn-cool-bg-color-7-start: #00C3FF; | |
| 154 | +$tn-cool-bg-color-7-end: #58FFF5; | |
| 155 | + | |
| 156 | +$tn-cool-bg-color-8-start: #00d1FF; | |
| 157 | +$tn-cool-bg-color-8-end: #69FF97; | |
| 158 | + | |
| 159 | +$tn-cool-bg-color-9-start: #0FD893; | |
| 160 | +$tn-cool-bg-color-9-end: #29ECBF; | |
| 161 | + | |
| 162 | +$tn-cool-bg-color-10-start: #0FD850; | |
| 163 | +$tn-cool-bg-color-10-end: #F9F047; | |
| 164 | + | |
| 165 | +$tn-cool-bg-color-11-start: #24FE41; | |
| 166 | +$tn-cool-bg-color-11-end: #F7FD47; | |
| 167 | + | |
| 168 | +$tn-cool-bg-color-12-start: #D6FF7F; | |
| 169 | +$tn-cool-bg-color-12-end: #00F657; | |
| 170 | + | |
| 171 | +$tn-cool-bg-color-13-start: #FA709A; | |
| 172 | +$tn-cool-bg-color-13-end: #FEE140; | |
| 173 | + | |
| 174 | +$tn-cool-bg-color-14-start: #FE5E9C; | |
| 175 | +$tn-cool-bg-color-14-end: #F1AA76; | |
| 176 | + | |
| 177 | +$tn-cool-bg-color-15-start: #FF3181; | |
| 178 | +$tn-cool-bg-color-15-end: #FF8331; | |
| 179 | + | |
| 180 | +$tn-cool-bg-color-16-start: #ED1C24; | |
| 181 | +$tn-cool-bg-color-16-end: #FECE12; | |
| 182 | + | |
| 183 | + | ... | ... |