19 Commits
v0.1.4 ... main

Author SHA1 Message Date
xiaoshi
4b7da24066 Update xiaoshi-device-consumables-button.js 2025-11-29 23:55:48 +08:00
xiaoshi
721b6a4ba2 Delete xiaoshi-device-consumables-button2.js 2025-11-29 23:55:37 +08:00
xiaoshi
b615d3dd7a Update xiaoshi-device-todo-card.js 2025-11-29 20:08:41 +08:00
xiaoshi
6f58598f54 Update xiaoshi-device-update-card.js 2025-11-29 00:07:04 +08:00
xiaoshi
f71e51029c Update xiaoshi-device-ha-info-card.js 2025-11-29 00:05:21 +08:00
xiaoshi
48f0c23456 Update xiaoshi-device-update-card.js 2025-11-28 23:20:14 +08:00
xiaoshi
910365f8b8 Update xiaoshi-device-ha-info-card.js 2025-11-28 23:20:04 +08:00
xiaoshi
81b40138f5 Update xiaoshi-pad-card.js 2025-11-28 21:50:16 +08:00
xiaoshi
4783085a99 Update xiaoshi-device-update-card.js 2025-11-28 21:49:39 +08:00
xiaoshi
737b174953 Update xiaoshi-device-todo-card.js 2025-11-28 21:49:28 +08:00
xiaoshi
d49426da73 Update xiaoshi-device-offline-card.js 2025-11-28 21:49:16 +08:00
xiaoshi
3bf33ef0cb Update xiaoshi-device-ha-info-card.js 2025-11-28 21:49:02 +08:00
xiaoshi
2c3c3fd42d Update xiaoshi-device-consumables-card.js 2025-11-28 21:48:49 +08:00
xiaoshi
4fe21a2c74 Update xiaoshi-device-consumables-button2.js 2025-11-28 21:48:35 +08:00
xiaoshi
3900897f15 Update xiaoshi-device-consumables-button.js 2025-11-28 21:48:19 +08:00
xiaoshi
2170f5423c Update xiaoshi-device-balance-card.js 2025-11-28 21:48:06 +08:00
xiaoshi
82e71cf38d Update xiaoshi-device-consumables-button.js 2025-11-28 20:49:17 +08:00
xiaoshi
c79052b1e1 Update xiaoshi-device-consumables-button2.js 2025-11-28 20:49:01 +08:00
xiaoshi
5ef261877c Update xiaoshi-device-consumables-card.js 2025-11-28 20:48:46 +08:00
9 changed files with 372 additions and 2461 deletions

View File

@@ -975,12 +975,12 @@ class XiaoshiBalanceCard extends LitElement {
} }
_handleRefresh() { _handleRefresh() {
this._handleClick();
this._loadOilPriceData(); this._loadOilPriceData();
navigator.vibrate(50);
} }
_handleEntityClick(entity) { _handleEntityClick(entity) {
navigator.vibrate(50); this._handleClick();
// 点击实体时打开实体详情页 // 点击实体时打开实体详情页
if (entity.entity_id) { if (entity.entity_id) {
const evt = new Event('hass-more-info', { composed: true }); const evt = new Event('hass-more-info', { composed: true });
@@ -989,6 +989,17 @@ class XiaoshiBalanceCard extends LitElement {
} }
} }
_handleClick(){
if (navigator.vibrate) {
navigator.vibrate(50);
}
else if (navigator.webkitVibrate) {
navigator.webkitVibrate(50);
}
else {
}
}
_evaluateWarningCondition(value, condition) { _evaluateWarningCondition(value, condition) {
if (!condition) return false; if (!condition) return false;

View File

@@ -291,9 +291,17 @@ class XiaoshiConsumablesButtonEditor extends LitElement {
</div> </div>
<div class="form-group"> <div class="form-group">
<label> </label> <label>👇👇👇下方弹出的卡片可增加的其他卡片👇👇👇</label>
<label>👇👇👇下面是弹出卡片内容👇👇👇</label> <textarea
<label> </label> @change=${this._entityChanged}
.value=${this.config.other_cards || ''}
name="other_cards"
placeholder='# 示例配置添加button卡片
- type: custom:button-card
template: 测试模板(最好引用模板,否则大概率会报错)
- type: custom:button-card
template: 测试模板(最好引用模板,否则大概率会报错)'>
</textarea>
</div> </div>
<div class="checkbox-group"> <div class="checkbox-group">
@@ -301,11 +309,19 @@ class XiaoshiConsumablesButtonEditor extends LitElement {
type="checkbox" type="checkbox"
class="checkbox-input" class="checkbox-input"
@change=${this._entityChanged} @change=${this._entityChanged}
.checked=${this.config.show_preview !== false} .checked=${this.config.no_preview === true}
name="show_preview" name="no_preview"
id="show_preview" id="no_preview"
/> />
<label for="show_preview" class="checkbox-label" style="color: red;"> 弹出卡片预览(正式使用时取消勾选)</label> <label for="no_preview" class="checkbox-label" style="color: red;">
📻显示预览📻( 请先勾选测试显示效果
</label>
</div>
<div class="form-group">
<label> </label>
<label>👇👇👇下方是弹出的主卡配置项👇👇👇</label>
<label> </label>
</div> </div>
<!-- button新元素 结束--> <!-- button新元素 结束-->
@@ -532,17 +548,15 @@ class XiaoshiConsumablesButtonEditor extends LitElement {
</div> </div>
<div class="help-text"> <div class="help-text">
搜索并选择要显示的设备耗材实体,支持多选。每个实体可以配置:<br> 搜索并选择要显示的设备耗材实体,支持多选。每个实体可以配置:<br>
• <strong>特殊实体显示:</strong>binary_sensor(off→正常,on→缺少), event(unknown→正常,其他→低电量)<br>
• 属性名:留空使用实体状态,或输入属性名<br> • 属性名:留空使用实体状态,或输入属性名<br>
• 名称重定义:勾选后可自定义显示名称<br> • 名称重定义:勾选后可自定义显示名称<br>
• 图标重定义:勾选后可自定义图标(如 mdi:phone<br> • 图标重定义:勾选后可自定义图标(如 mdi:phone<br>
• 单位重定义:勾选后可自定义单位(如 元、$、kWh 等)<br> • 单位重定义:勾选后可自定义单位(如 元、$、kWh 等)<br>
• 预警条件:勾选后设置预警条件,支持 >10, >=10, <10, <=10, ==10, ==on, ==off, =="hello world" 等<br> • 预警条件:勾选后设置预警条件,支持 >10, >=10, <10, <=10, ==10, ==on, ==off, =="hello world" 等<br>
• 换算:对数值进行数学运算,支持 +10, -10, *1.5, /2 等<br> • 换算:对数值进行数学运算,支持 +10, -10, *1.5, /2 等<br>
• 未勾选重定义时,将使用实体的原始属性值 </div>
</div> </div>
</div> </div>
</div>
`; `;
} }
@@ -553,7 +567,6 @@ class XiaoshiConsumablesButtonEditor extends LitElement {
const { name, value, type, checked } = e.target; const { name, value, type, checked } = e.target;
let finalValue; let finalValue;
// 处理复选框 // 处理复选框
if (type === 'checkbox') { if (type === 'checkbox') {
finalValue = checked; finalValue = checked;
@@ -770,9 +783,11 @@ class XiaoshiConsumablesButtonEditor extends LitElement {
this._showEntityList = false; this._showEntityList = false;
} }
/*button新按钮方法 开始*/
setConfig(config) { setConfig(config) {
this.config = config; this.config = config || {};
} }
/*button新按钮方法 结束*/
} }
customElements.define('xiaoshi-consumables-button-editor', XiaoshiConsumablesButtonEditor); customElements.define('xiaoshi-consumables-button-editor', XiaoshiConsumablesButtonEditor);
@@ -1044,7 +1059,7 @@ class XiaoshiConsumablesButton extends LitElement {
margin-right: 8px; margin-right: 8px;
color: var(--fg-color, #000); color: var(--fg-color, #000);
flex-shrink: 0; flex-shrink: 0;
font-size: 10px; font-size: 11px;
width: 12px; width: 12px;
height: 12px; height: 12px;
display: flex; display: flex;
@@ -1054,7 +1069,7 @@ class XiaoshiConsumablesButton extends LitElement {
.device-name { .device-name {
color: var(--fg-color, #000); color: var(--fg-color, #000);
font-size: 9px; font-size: 11px;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
@@ -1064,13 +1079,12 @@ class XiaoshiConsumablesButton extends LitElement {
.device-value { .device-value {
color: var(--fg-color, #000); color: var(--fg-color, #000);
font-size: 9px; font-size: 11px;
flex-shrink: 0; flex-shrink: 0;
font-weight: bold; font-weight: bold;
max-width: 45%; max-width: 45%;
text-align: right; text-align: right;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
} }
@@ -1079,7 +1093,7 @@ class XiaoshiConsumablesButton extends LitElement {
} }
.device-unit { .device-unit {
font-size: 9px; font-size: 11px;
color: var(--fg-color, #000); color: var(--fg-color, #000);
margin-left: 0.5px; margin-left: 0.5px;
font-weight: bold; font-weight: bold;
@@ -1261,12 +1275,12 @@ class XiaoshiConsumablesButton extends LitElement {
} }
_handleRefresh() { _handleRefresh() {
this._handleClick();
this._loadOilPriceData(); this._loadOilPriceData();
navigator.vibrate(50);
} }
_handleEntityClick(entity) { _handleEntityClick(entity) {
navigator.vibrate(50); this._handleClick();
// 点击实体时打开实体详情页 // 点击实体时打开实体详情页
if (entity.entity_id) { if (entity.entity_id) {
const evt = new Event('hass-more-info', { composed: true }); const evt = new Event('hass-more-info', { composed: true });
@@ -1274,24 +1288,69 @@ class XiaoshiConsumablesButton extends LitElement {
this.dispatchEvent(evt); this.dispatchEvent(evt);
} }
} }
_handleClick(){
if (navigator.vibrate) {
navigator.vibrate(50);
}
else if (navigator.webkitVibrate) {
navigator.webkitVibrate(50);
}
else {
}
}
/*button新元素 开始*/ /*button新元素 开始*/
_handleButtonClick() { _handleButtonClick() {
const tapAction = this.config.tap_action; const tapAction = this.config.tap_action;
if (!tapAction || tapAction !== 'none') { if (!tapAction || tapAction !== 'none') {
// 默认 tap_action 行为:弹出耗材卡片 // 默认 tap_action 行为:弹出垂直堆叠卡片
const excludedParams = ['type', 'button_height', 'button_width', 'button_font_size', 'button_icon_size', 'show_preview', 'tap_action']; const excludedParams = ['type', 'button_height', 'button_width', 'button_font_size', 'button_icon_size', 'show_preview', 'tap_action'];
const cardConfig = {};
// 构建垂直堆叠卡片的内容
const cards = [];
// 1. 添加耗材卡片
const consumablesCardConfig = {};
Object.keys(this.config).forEach(key => { Object.keys(this.config).forEach(key => {
if (!excludedParams.includes(key)) { if (!excludedParams.includes(key) && key !== 'other_cards' && key !== 'no_preview') {
cardConfig[key] = this.config[key]; consumablesCardConfig[key] = this.config[key];
} }
}); });
const popupContent = { cards.push({
type: 'custom:xiaoshi-consumables-card', type: 'custom:xiaoshi-consumables-card',
...cardConfig ...consumablesCardConfig
});
// 2. 添加附加卡片
if (this.config.other_cards && this.config.other_cards.trim()) {
try {
const additionalCardsConfig = this._parseYamlCards(this.config.other_cards);
// 为每个附加卡片传递 theme 值
const cardsWithTheme = additionalCardsConfig.map(card => {
// 如果卡片没有 theme 配置,则从当前卡片配置中传递
if (!card.theme && this.config.theme) {
return {
...card,
theme: this.config.theme
};
}
return card;
});
cards.push(...cardsWithTheme);
} catch (error) {
console.error('解析附加卡片配置失败:', error);
}
}
// 创建垂直堆叠卡片
const popupContent = {
type: 'vertical-stack',
cards: cards
}; };
const popupStyle = this.config.popup_style || ` const popupStyle = this.config.popup_style || `
@@ -1307,8 +1366,158 @@ class XiaoshiConsumablesButton extends LitElement {
console.warn('browser_mod not available, cannot show popup'); console.warn('browser_mod not available, cannot show popup');
} }
} }
navigator.vibrate(50); this._handleClick();
} }
_parseYamlCards(yamlString) {
try {
const lines = yamlString.split('\n');
const cards = [];
let currentCard = null;
let indentStack = [];
let contextStack = [];
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
const trimmed = line.trim();
if (!trimmed || trimmed.startsWith('#')) continue;
const indentLevel = line.length - line.trimStart().length;
if (trimmed.startsWith('- type')) {
if (currentCard) {
cards.push(currentCard);
currentCard = null;
indentStack = [];
contextStack = [];
}
const content = trimmed.substring(1).trim();
if (content.includes(':')) {
const [key, ...valueParts] = content.split(':');
const value = valueParts.join(':').trim();
currentCard = {};
this._setNestedValue(currentCard, key.trim(), this._parseValue(value));
} else {
currentCard = { type: content };
}
indentStack = [indentLevel];
contextStack = [currentCard];
} else if (currentCard && trimmed.startsWith('-')) {
while (indentStack.length > 1 && indentLevel <= indentStack[indentStack.length - 1]) {
indentStack.pop();
contextStack.pop();
}
let currentContext = contextStack[contextStack.length - 1];
const itemValue = trimmed.substring(1).trim();
if (!Array.isArray(currentContext)) {
if (contextStack.length > 1) {
const parentContext = contextStack[contextStack.length - 2];
for (let key in parentContext) {
if (parentContext[key] === currentContext) {
parentContext[key] = [];
contextStack[contextStack.length - 1] = parentContext[key];
currentContext = parentContext[key];
break;
}
}
}
}
if (Array.isArray(currentContext)) {
if (itemValue.includes(':')) {
const [key, ...valueParts] = itemValue.split(':');
const value = valueParts.join(':').trim();
const obj = {};
obj[key.trim()] = this._parseValue(value);
currentContext.push(obj);
} else {
currentContext.push(this._parseValue(itemValue));
}
}
} else if (currentCard && trimmed.includes(':')) {
const [key, ...valueParts] = trimmed.split(':');
const value = valueParts.join(':').trim();
const keyName = key.trim();
while (indentStack.length > 1 && indentLevel <= indentStack[indentStack.length - 1]) {
indentStack.pop();
contextStack.pop();
}
const currentContext = contextStack[contextStack.length - 1];
if (value) {
this._setNestedValue(currentContext, keyName, this._parseValue(value));
} else {
let nextLine = null, nextIndent = null;
for (let j = i + 1; j < lines.length; j++) {
const nextTrimmed = lines[j].trim();
if (nextTrimmed && !nextTrimmed.startsWith('#')) {
nextLine = nextTrimmed;
nextIndent = lines[j].length - lines[j].trimStart().length;
break;
}
}
currentContext[keyName] = (nextLine && nextLine.startsWith('-') && nextIndent > indentLevel)
? [] : (currentContext[keyName] || {});
indentStack.push(indentLevel);
contextStack.push(currentContext[keyName]);
}
}
}
if (currentCard) cards.push(currentCard);
return cards;
} catch (error) {
console.error('YAML解析错误:', error);
return [];
}
}
_parseValue(value) {
if (!value) return '';
// 移除引号
if ((value.startsWith('"') && value.endsWith('"')) ||
(value.startsWith("'") && value.endsWith("'"))) {
return value.slice(1, -1);
}
// 尝试解析为数字
if (!isNaN(value) && value.trim() !== '') {
return Number(value);
}
// 尝试解析为布尔值
if (value === 'true') return true;
if (value === 'false') return false;
if (value === 'null') return null;
// 返回字符串
return value;
}
_setNestedValue(obj, path, value) {
// 支持嵌套路径,如 "styles.card"
const keys = path.split('.');
let current = obj;
for (let i = 0; i < keys.length - 1; i++) {
const key = keys[i];
if (!current[key] || typeof current[key] !== 'object') {
current[key] = {};
}
current = current[key];
}
current[keys[keys.length - 1]] = value;
}
/*button新元素 结束*/ /*button新元素 结束*/
_renderDeviceItem(consumablesData) { _renderDeviceItem(consumablesData) {
@@ -1437,7 +1646,6 @@ class XiaoshiConsumablesButton extends LitElement {
return false; return false;
} }
render() { render() {
if (!this.hass) { if (!this.hass) {
return html`<div class="loading">等待Home Assistant连接...</div>`; return html`<div class="loading">等待Home Assistant连接...</div>`;
@@ -1472,7 +1680,7 @@ class XiaoshiConsumablesButton extends LitElement {
}).length; }).length;
/*button新元素 前9行和最后1行开始*/ /*button新元素 前9行和最后1行开始*/
const showPreview = this.config.show_preview !== false; const showPreview = this.config.no_preview === true;
return html` return html`
<div class="consumables-status" style="--fg-color: ${fgColor}; --bg-color: ${bgColor};" @click=${this._handleButtonClick}> <div class="consumables-status" style="--fg-color: ${fgColor}; --bg-color: ${bgColor};" @click=${this._handleButtonClick}>
@@ -1517,9 +1725,11 @@ class XiaoshiConsumablesButton extends LitElement {
} }
setConfig(config) { setConfig(config) {
this.config = config;
/*button新元素 开始*/ /*button新元素 开始*/
// 不设置默认值,只有明确配置时才添加 no_preview
this.config = {
...config
};
if (config.button_width) { if (config.button_width) {
this.style.setProperty('--button-width', config.button_width); this.style.setProperty('--button-width', config.button_width);
} else { } else {
@@ -1567,3 +1777,4 @@ class XiaoshiConsumablesButton extends LitElement {
} }
} }
customElements.define('xiaoshi-consumables-button', XiaoshiConsumablesButton); customElements.define('xiaoshi-consumables-button', XiaoshiConsumablesButton);

File diff suppressed because it is too large Load Diff

View File

@@ -906,7 +906,7 @@ class XiaoshiConsumablesCard extends LitElement {
.device-name { .device-name {
color: var(--fg-color, #000); color: var(--fg-color, #000);
font-size: 9px; font-size: 11px;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
@@ -916,13 +916,12 @@ class XiaoshiConsumablesCard extends LitElement {
.device-value { .device-value {
color: var(--fg-color, #000); color: var(--fg-color, #000);
font-size: 9px; font-size: 11px;
flex-shrink: 0; flex-shrink: 0;
font-weight: bold; font-weight: bold;
max-width: 45%; max-width: 45%;
text-align: right; text-align: right;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
} }
@@ -931,7 +930,7 @@ class XiaoshiConsumablesCard extends LitElement {
} }
.device-unit { .device-unit {
font-size: 9px; font-size: 11px;
color: var(--fg-color, #000); color: var(--fg-color, #000);
margin-left: 0.5px; margin-left: 0.5px;
font-weight: bold; font-weight: bold;
@@ -1113,12 +1112,12 @@ class XiaoshiConsumablesCard extends LitElement {
} }
_handleRefresh() { _handleRefresh() {
this._handleClick();
this._loadOilPriceData(); this._loadOilPriceData();
navigator.vibrate(50);
} }
_handleEntityClick(entity) { _handleEntityClick(entity) {
navigator.vibrate(50); this._handleClick();
// 点击实体时打开实体详情页 // 点击实体时打开实体详情页
if (entity.entity_id) { if (entity.entity_id) {
const evt = new Event('hass-more-info', { composed: true }); const evt = new Event('hass-more-info', { composed: true });
@@ -1127,6 +1126,17 @@ class XiaoshiConsumablesCard extends LitElement {
} }
} }
_handleClick(){
if (navigator.vibrate) {
navigator.vibrate(50);
}
else if (navigator.webkitVibrate) {
navigator.webkitVibrate(50);
}
else {
}
}
_renderDeviceItem(consumablesData) { _renderDeviceItem(consumablesData) {
let isWarning = false; let isWarning = false;

View File

@@ -766,6 +766,14 @@ export class XiaoshiHaInfoCard extends LitElement {
if (entityId.startsWith('climate.')) return 'mdi:thermostat'; if (entityId.startsWith('climate.')) return 'mdi:thermostat';
if (entityId.startsWith('cover.')) return 'mdi:window-shutter'; if (entityId.startsWith('cover.')) return 'mdi:window-shutter';
if (entityId.startsWith('weather.')) return 'mdi:weather-cloudy'; if (entityId.startsWith('weather.')) return 'mdi:weather-cloudy';
if (entityId.startsWith('input_select.')) return 'mdi:form-select';
if (entityId.startsWith('select.')) return 'mdi:form-select';
if (entityId.startsWith('input_text.')) return 'mdi:form-textbox';
if (entityId.startsWith('text.')) return 'mdi:form-textbox';
if (entityId.startsWith('button.')) return 'mdi:button-pointer';
if (entityId.startsWith('event.')) return 'mdi:gesture-tap-button';
if (entityId.startsWith('device_tracker.')) return 'mdi:lan-connect';
if (entityId.startsWith('notify.')) return 'mdi:message';
return 'mdi:help-circle'; return 'mdi:help-circle';
} }
@@ -788,13 +796,13 @@ export class XiaoshiHaInfoCard extends LitElement {
} }
_handleRefresh() { _handleRefresh() {
this._handleClick();
this._loadOfflineDevices(); this._loadOfflineDevices();
navigator.vibrate(50);
} }
_handleDeviceClick(device) { _handleDeviceClick(device) {
navigator.vibrate(50);
// 点击设备时跳转到设备详情页 // 点击设备时跳转到设备详情页
this._handleClick();
if (device.device_id) { if (device.device_id) {
// 先关闭当前弹窗/界面 // 先关闭当前弹窗/界面
this._closeCurrentDialog(); this._closeCurrentDialog();
@@ -817,7 +825,7 @@ export class XiaoshiHaInfoCard extends LitElement {
} }
_handleEntityClick(entity) { _handleEntityClick(entity) {
navigator.vibrate(50); this._handleClick();
// 点击实体时打开实体详情页 // 点击实体时打开实体详情页
if (entity.entity_id) { if (entity.entity_id) {
// 使用您建议的第一种方式 // 使用您建议的第一种方式
@@ -827,6 +835,17 @@ export class XiaoshiHaInfoCard extends LitElement {
} }
} }
_handleClick(){
if (navigator.vibrate) {
navigator.vibrate(50);
}
else if (navigator.webkitVibrate) {
navigator.webkitVibrate(50);
}
else {
}
}
_closeCurrentDialog() { _closeCurrentDialog() {
// 查找并关闭当前可能的弹窗或对话框 // 查找并关闭当前可能的弹窗或对话框
const dialogs = document.querySelectorAll('ha-dialog, .mdc-dialog, paper-dialog, vaadin-dialog'); const dialogs = document.querySelectorAll('ha-dialog, .mdc-dialog, paper-dialog, vaadin-dialog');
@@ -907,6 +926,12 @@ export class XiaoshiHaInfoCard extends LitElement {
} }
} }
// 新增规则如果skipped_version为null情况下当latest_version !== installed_version时
// 且实体状态为off时有可能是安装的版本比latest_version还高这种不算更新的实体
if (attributes.skipped_version === null && entity.state === 'off') {
return; // 跳过此更新
}
const updateData = { const updateData = {
name: attributes.friendly_name || entity.entity_id.replace('update.', ''), name: attributes.friendly_name || entity.entity_id.replace('update.', ''),
current_version: attributes.installed_version, current_version: attributes.installed_version,
@@ -946,14 +971,14 @@ export class XiaoshiHaInfoCard extends LitElement {
} }
_handleRefresh() { _handleRefresh() {
this._handleClick();
this._loadUpdateData(); this._loadUpdateData();
this._loadOfflineDevices(); this._loadOfflineDevices();
navigator.vibrate(50);
} }
_handleUpdateClick(update) { _handleUpdateClick(update) {
navigator.vibrate(50);
// 点击更新项时弹出实体详情 // 点击更新项时弹出实体详情
this._handleClick();
// 如果有entity_id弹出实体详情 // 如果有entity_id弹出实体详情
if (update.entity_id) { if (update.entity_id) {
@@ -974,7 +999,7 @@ export class XiaoshiHaInfoCard extends LitElement {
_handleConfirmUpdate(update, event) { _handleConfirmUpdate(update, event) {
event.stopPropagation(); // 阻止事件冒泡 event.stopPropagation(); // 阻止事件冒泡
event.preventDefault(); // 阻止默认行为 event.preventDefault(); // 阻止默认行为
navigator.vibrate(50); this._handleClick();
// 弹出确认对话框 // 弹出确认对话框
const confirmed = confirm(`确认要更新 ${update.name} 吗?\n当前版本: ${update.current_version}\n最新版本: ${update.latest_version}`); const confirmed = confirm(`确认要更新 ${update.name} 吗?\n当前版本: ${update.current_version}\n最新版本: ${update.latest_version}`);
@@ -986,6 +1011,7 @@ export class XiaoshiHaInfoCard extends LitElement {
this._loadUpdateData(); this._loadUpdateData();
}, 1000); }, 1000);
} }
} }
_executeUpdate(update) { _executeUpdate(update) {
@@ -1249,7 +1275,7 @@ export class XiaoshiHaInfoCard extends LitElement {
<div class="device-name">${update.name}</div> <div class="device-name">${update.name}</div>
<div class="device-details"> <div class="device-details">
当前版本: ${update.current_version} → 最新版本: ${update.latest_version} 当前版本: ${update.current_version} → 最新版本: ${update.latest_version}
${update.skipped_version ? html`<span style="color: #ff9800;"> 已跳过版本: ${update.skipped_version}</span>` : ''} ${update.skipped_version ? html`<br><span style="color: #ff9800;">已跳过版本: ${update.skipped_version}</span>` : ''}
</div> </div>
</div> </div>
<div class="device-last-seen-update" @click=${(e) => this._handleConfirmUpdate(update, e)}> <div class="device-last-seen-update" @click=${(e) => this._handleConfirmUpdate(update, e)}>
@@ -1274,7 +1300,7 @@ export class XiaoshiHaInfoCard extends LitElement {
<div class="device-name">${update.name}</div> <div class="device-name">${update.name}</div>
<div class="device-details"> <div class="device-details">
当前版本: ${update.current_version} → 最新版本: ${update.latest_version} 当前版本: ${update.current_version} → 最新版本: ${update.latest_version}
${update.skipped_version ? html`<span style="color: #ff9800;"> 已跳过版本: ${update.skipped_version}</span>` : ''} ${update.skipped_version ? html`<br><span style="color: #ff9800;">已跳过版本: ${update.skipped_version}</span>` : ''}
</div> </div>
</div> </div>
<div class="device-last-seen-update" @click=${(e) => this._handleConfirmUpdate(update, e)}> <div class="device-last-seen-update" @click=${(e) => this._handleConfirmUpdate(update, e)}>

View File

@@ -667,12 +667,12 @@ export class XiaoshiOfflineCard extends LitElement {
} }
_handleRefresh() { _handleRefresh() {
this._handleClick();
this._loadOfflineDevices(); this._loadOfflineDevices();
navigator.vibrate(50);
} }
_handleDeviceClick(device) { _handleDeviceClick(device) {
navigator.vibrate(50); this._handleClick();
// 点击设备时跳转到设备详情页 // 点击设备时跳转到设备详情页
if (device.device_id) { if (device.device_id) {
// 先关闭当前弹窗/界面 // 先关闭当前弹窗/界面
@@ -696,7 +696,7 @@ export class XiaoshiOfflineCard extends LitElement {
} }
_handleEntityClick(entity) { _handleEntityClick(entity) {
navigator.vibrate(50); this._handleClick();
// 点击实体时打开实体详情页 // 点击实体时打开实体详情页
if (entity.entity_id) { if (entity.entity_id) {
// 使用您建议的第一种方式 // 使用您建议的第一种方式
@@ -706,6 +706,17 @@ export class XiaoshiOfflineCard extends LitElement {
} }
} }
_handleClick(){
if (navigator.vibrate) {
navigator.vibrate(50);
}
else if (navigator.webkitVibrate) {
navigator.webkitVibrate(50);
}
else {
}
}
_closeCurrentDialog() { _closeCurrentDialog() {
// 查找并关闭当前可能的弹窗或对话框 // 查找并关闭当前可能的弹窗或对话框
const dialogs = document.querySelectorAll('ha-dialog, .mdc-dialog, paper-dialog, vaadin-dialog'); const dialogs = document.querySelectorAll('ha-dialog, .mdc-dialog, paper-dialog, vaadin-dialog');

View File

@@ -941,12 +941,12 @@ class XiaoshiTodoCard extends LitElement {
} }
_handleRefresh() { _handleRefresh() {
this._handleClick();
this._loadTodoData(); this._loadTodoData();
navigator.vibrate(50);
} }
_handleEntityClick(entity) { _handleEntityClick(entity) {
navigator.vibrate(50); this._handleClick();
// 点击实体时打开实体详情页 // 点击实体时打开实体详情页
if (entity.entity_id) { if (entity.entity_id) {
const evt = new Event('hass-more-info', { composed: true }); const evt = new Event('hass-more-info', { composed: true });
@@ -955,6 +955,17 @@ class XiaoshiTodoCard extends LitElement {
} }
} }
_handleClick(){
if (navigator.vibrate) {
navigator.vibrate(50);
}
else if (navigator.webkitVibrate) {
navigator.webkitVibrate(50);
}
else {
}
}
async _addTodoItem(entityId, item, description = '', due = '') { async _addTodoItem(entityId, item, description = '', due = '') {
try { try {
const params = { const params = {
@@ -1109,7 +1120,10 @@ class XiaoshiTodoCard extends LitElement {
<input <input
type="checkbox" type="checkbox"
.checked=${item.status === 'completed'} .checked=${item.status === 'completed'}
@change=${(e) => this._updateTodoItem(todoData.entity_id, item.summary || item.uid, e.target.checked ? 'completed' : 'needs_action')} @change=${(e) => {
this._updateTodoItem(todoData.entity_id, item.summary || item.uid, e.target.checked ? 'completed' : 'needs_action');
this._handleClick();
}}
style="margin-right: 8px; margin-top: 2px;" style="margin-right: 8px; margin-top: 2px;"
/> />
${isEditing ? html` ${isEditing ? html`
@@ -1142,6 +1156,7 @@ class XiaoshiTodoCard extends LitElement {
@input=${(e) => { @input=${(e) => {
this._editingItem.due = e.target.value; this._editingItem.due = e.target.value;
this.requestUpdate(); this.requestUpdate();
this._handleClick();
}} }}
/> />
<button <button
@@ -1150,6 +1165,7 @@ class XiaoshiTodoCard extends LitElement {
this._editTodoItem(todoData.entity_id, item.summary || item.uid, this._editingItem.summary, this._editingItem.description, this._editingItem.due); this._editTodoItem(todoData.entity_id, item.summary || item.uid, this._editingItem.summary, this._editingItem.description, this._editingItem.due);
this._editingItem = null; this._editingItem = null;
this.requestUpdate(); this.requestUpdate();
this._handleClick();
}} }}
> >
保存 保存
@@ -1159,6 +1175,7 @@ class XiaoshiTodoCard extends LitElement {
@click=${() => { @click=${() => {
this._editingItem = null; this._editingItem = null;
this.requestUpdate(); this.requestUpdate();
this._handleClick();
}} }}
> >
取消 取消
@@ -1186,6 +1203,7 @@ class XiaoshiTodoCard extends LitElement {
due: this._formatDateForInput(item.due) || '' due: this._formatDateForInput(item.due) || ''
}; };
this.requestUpdate(); this.requestUpdate();
this._handleClick();
}} }}
style="margin-left: 8px; margin-top: 2px;" style="margin-left: 8px; margin-top: 2px;"
title="修改" title="修改"
@@ -1195,7 +1213,10 @@ class XiaoshiTodoCard extends LitElement {
` : ''} ` : ''}
<button <button
class="remove-btn" class="remove-btn"
@click=${() => this._removeTodoItem(todoData.entity_id, item.summary || item.uid)} @click=${() => {
this._removeTodoItem(todoData.entity_id, item.summary || item.uid);
this._handleClick();
}}
style="margin-left: 4px; margin-top: 2px;" style="margin-left: 4px; margin-top: 2px;"
title="删除" title="删除"
> >
@@ -1216,6 +1237,7 @@ class XiaoshiTodoCard extends LitElement {
[todoData.entity_id]: !this._expandedAddForm[todoData.entity_id] [todoData.entity_id]: !this._expandedAddForm[todoData.entity_id]
}; };
this.requestUpdate(); this.requestUpdate();
this._handleClick();
}} }}
> >
${this._expandedAddForm[todoData.entity_id] ? '收起' : '添加新待办事项'} ${this._expandedAddForm[todoData.entity_id] ? '收起' : '添加新待办事项'}
@@ -1263,6 +1285,7 @@ class XiaoshiTodoCard extends LitElement {
descInput.value = ''; descInput.value = '';
dateInput.value = ''; dateInput.value = '';
} }
this._handleClick();
}} }}
> >
添加 添加

View File

@@ -468,7 +468,7 @@ export class XiaoshiUpdateCard extends LitElement {
} }
_handleEntityClick(entity) { _handleEntityClick(entity) {
navigator.vibrate(50); this._handleClick();
// 点击实体时打开实体详情页 // 点击实体时打开实体详情页
if (entity.entity_id) { if (entity.entity_id) {
// 使用您建议的第一种方式 // 使用您建议的第一种方式
@@ -478,6 +478,17 @@ export class XiaoshiUpdateCard extends LitElement {
} }
} }
_handleClick(){
if (navigator.vibrate) {
navigator.vibrate(50);
}
else if (navigator.webkitVibrate) {
navigator.webkitVibrate(50);
}
else {
}
}
async _loadUpdateData() { async _loadUpdateData() {
if (!this.hass) return; if (!this.hass) return;
@@ -512,6 +523,11 @@ export class XiaoshiUpdateCard extends LitElement {
return; // 跳过此更新 return; // 跳过此更新
} }
} }
// 新增规则如果skipped_version为null情况下当latest_version !== installed_version时
// 且实体状态为off时有可能是安装的版本比latest_version还高这种不算更新的实体
if (attributes.skipped_version === null && entity.state === 'off') {
return; // 跳过此更新
}
const updateData = { const updateData = {
name: attributes.friendly_name || entity.entity_id.replace('update.', ''), name: attributes.friendly_name || entity.entity_id.replace('update.', ''),
@@ -552,12 +568,12 @@ export class XiaoshiUpdateCard extends LitElement {
} }
_handleRefresh() { _handleRefresh() {
this._handleClick();
this._loadUpdateData(); this._loadUpdateData();
navigator.vibrate(50);
} }
_handleUpdateClick(update) { _handleUpdateClick(update) {
navigator.vibrate(50); this._handleClick();
// 点击更新项时弹出实体详情 // 点击更新项时弹出实体详情
// 如果有entity_id弹出实体详情 // 如果有entity_id弹出实体详情
@@ -579,7 +595,7 @@ export class XiaoshiUpdateCard extends LitElement {
_handleConfirmUpdate(update, event) { _handleConfirmUpdate(update, event) {
event.stopPropagation(); // 阻止事件冒泡 event.stopPropagation(); // 阻止事件冒泡
event.preventDefault(); // 阻止默认行为 event.preventDefault(); // 阻止默认行为
navigator.vibrate(50); this._handleClick();
// 弹出确认对话框 // 弹出确认对话框
const confirmed = confirm(`确认要更新 ${update.name} 吗?\n当前版本: ${update.current_version}\n最新版本: ${update.latest_version}`); const confirmed = confirm(`确认要更新 ${update.name} 吗?\n当前版本: ${update.current_version}\n最新版本: ${update.latest_version}`);
@@ -854,7 +870,7 @@ export class XiaoshiUpdateCard extends LitElement {
<div class="device-name">${update.name}</div> <div class="device-name">${update.name}</div>
<div class="device-details"> <div class="device-details">
当前版本: ${update.current_version} → 最新版本: ${update.latest_version} 当前版本: ${update.current_version} → 最新版本: ${update.latest_version}
${update.skipped_version ? html`<span style="color: #ff9800;"> 已跳过版本: ${update.skipped_version}</span>` : ''} ${update.skipped_version ? html`<br><span style="color: #ff9800;">已跳过版本: ${update.skipped_version}</span>` : ''}
</div> </div>
</div> </div>
<div class="device-last-seen" @click=${(e) => this._handleConfirmUpdate(update, e)}> <div class="device-last-seen" @click=${(e) => this._handleConfirmUpdate(update, e)}>
@@ -879,7 +895,7 @@ export class XiaoshiUpdateCard extends LitElement {
<div class="device-name">${update.name}</div> <div class="device-name">${update.name}</div>
<div class="device-details"> <div class="device-details">
当前版本: ${update.current_version} → 最新版本: ${update.latest_version} 当前版本: ${update.current_version} → 最新版本: ${update.latest_version}
${update.skipped_version ? html`<span style="color: #ff9800;"> 已跳过版本: ${update.skipped_version}</span>` : ''} ${update.skipped_version ? html`<br><span style="color: #ff9800;"> 已跳过版本: ${update.skipped_version}</span>` : ''}
</div> </div>
</div> </div>
<div class="device-last-seen" @click=${(e) => this._handleConfirmUpdate(update, e)}> <div class="device-last-seen" @click=${(e) => this._handleConfirmUpdate(update, e)}>

View File

@@ -1,4 +1,4 @@
console.info("%c 消逝卡-平板端 \n%c v 0.1.4 ", "color: red; font-weight: bold; background: black", "color: white; font-weight: bold; background: black"); console.info("%c 消逝卡-平板端 \n%c v 0.1.5 ", "color: red; font-weight: bold; background: black", "color: white; font-weight: bold; background: black");
const loadCards = async () => { const loadCards = async () => {
await import('./xiaoshi-pad-grid-card.js'); await import('./xiaoshi-pad-grid-card.js');