@@ -0,0 +1 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
@@ -0,0 +1,29 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
{
|
||||
'name': "ylhc_list",
|
||||
|
||||
'summary': "advance list for odoo",
|
||||
|
||||
'description': """
|
||||
advance list
|
||||
fixed column list
|
||||
""",
|
||||
|
||||
'author': "crax",
|
||||
'website': "https://www.ylhc.com",
|
||||
|
||||
'category': 'apps/list',
|
||||
'version': '17.0.0.1',
|
||||
|
||||
'depends': ['base', 'web'],
|
||||
'price': 9999,
|
||||
|
||||
'data': [],
|
||||
|
||||
'assets': {
|
||||
'web.assets_backend': [
|
||||
'ylhc_list/static/src/*.*'
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_xc_list_xc_list,xc_list.xc_list,model_xc_list_xc_list,base.group_user,1,1,1,1
|
||||
|
Binary file not shown.
|
After Width: | Height: | Size: 62 KiB |
@@ -0,0 +1,9 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
import { ListController } from "@web/views/list/list_controller";
|
||||
|
||||
export class YlhcListController extends ListController {
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { ListRenderer } from "@web/views/list/list_renderer";
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
import { xml } from "@odoo/owl";
|
||||
|
||||
export class YlhcListRenderer extends ListRenderer {
|
||||
|
||||
setup() {
|
||||
super.setup();
|
||||
|
||||
this.hasExpander = this._hasExpander();
|
||||
this.subRowTemplate = this.getSubRowTemplate();
|
||||
}
|
||||
|
||||
/**
|
||||
* check if tree_column in column option
|
||||
*/
|
||||
isTreeColumn(column) {
|
||||
return column.options.tree_column;
|
||||
}
|
||||
|
||||
isExpanderColumn(column) {
|
||||
return column.options.expander;
|
||||
}
|
||||
|
||||
_hasExpander() {
|
||||
let columns = this.state.columns || [];
|
||||
for (let i = 0; i < columns.length; i++) {
|
||||
if (this.isExpanderColumn(columns[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
getSubRowTemplate() {
|
||||
let columns = this.state.columns || [];
|
||||
for (let i = 0; i < columns.length; i++) {
|
||||
if (this.isExpanderColumn(columns[i])) {
|
||||
let sub_row_template = columns[i].options.sub_row_template;
|
||||
if (columns[i].options.sub_row_template) {
|
||||
return sub_row_template;
|
||||
}
|
||||
}
|
||||
}
|
||||
return xml`<div>can find the sub rwo template !!!</div>`;
|
||||
}
|
||||
|
||||
getSubRowColumnSpan() {
|
||||
let columns = this.state.columns || [];
|
||||
if (this.hasSelectors) {
|
||||
return columns.length + 1;
|
||||
}
|
||||
return columns.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* parent_path is used to check if the column is a tree column
|
||||
*/
|
||||
checkParentPath() {
|
||||
let columns = this.state.columns || [];
|
||||
// find parent path
|
||||
let parentPath = columns.find(column => column.name == 'parent_path');
|
||||
if (parentPath) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
getTreeLevel(record) {
|
||||
let parentPath = record.data.parent_path;
|
||||
if (parentPath) {
|
||||
return parentPath.split('/').length;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* get children of a record
|
||||
* @param {*} record
|
||||
* */
|
||||
hasChildren(record) {
|
||||
let records = this.props.list.records;
|
||||
let index = records.indexOf(record);
|
||||
let parent_path = record.data.parent_path;
|
||||
for (let i = index + 1; i < records.length; i++) {
|
||||
if (records[i].data.parent_path.startsWith(parent_path)) {
|
||||
return true
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
getChildren(record) {
|
||||
let records = this.props.list.records;
|
||||
let index = records.indexOf(record);
|
||||
let parent_path = record.data.parent_path;
|
||||
let children = [];
|
||||
for (let i = index + 1; i < records.length; i++) {
|
||||
if (records[i].data.parent_path.startsWith(parent_path)) {
|
||||
children.push(records[i]);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return children;
|
||||
}
|
||||
|
||||
/**
|
||||
* click the expand button
|
||||
**/
|
||||
toggleRecord(record) {
|
||||
let children = this.getChildren(record);
|
||||
if (record.folded) {
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
children[i].hide = false;
|
||||
}
|
||||
} else {
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
children[i].hide = true;
|
||||
}
|
||||
}
|
||||
record.folded = !record.folded;
|
||||
this.render();
|
||||
}
|
||||
|
||||
toggleExpander(record) {
|
||||
record.sub_row_folded = !record.sub_row_folded;
|
||||
this.render();
|
||||
}
|
||||
}
|
||||
|
||||
YlhcListRenderer.recordRowTemplate = "ylhc_list.ListRenderer.RecordRow";
|
||||
@@ -0,0 +1,154 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="ylhc_list.ListRenderer.RecordRow">
|
||||
<tr class="o_data_row"
|
||||
t-if="!record.hide"
|
||||
t-att-class="getRowClass(record)"
|
||||
t-att-data-id="record.id"
|
||||
t-on-click.capture="(ev) => this.onClickCapture(record, ev)"
|
||||
t-on-mouseover.capture="(ev) => this.ignoreEventInSelectionMode(ev)"
|
||||
t-on-mouseout.capture="(ev) => this.ignoreEventInSelectionMode(ev)"
|
||||
t-on-mouseenter.capture="(ev) => this.ignoreEventInSelectionMode(ev)"
|
||||
t-on-touchstart="(ev) => this.onRowTouchStart(record, ev)"
|
||||
t-on-touchend="() => this.onRowTouchEnd(record)"
|
||||
t-on-touchmove="() => this.onRowTouchMove(record)"
|
||||
>
|
||||
<td t-on-keydown.synthetic="(ev) => this.onCellKeydown(ev, group, record)" t-if="hasSelectors" class="o_list_record_selector user-select-none" t-on-click.stop="() => this.toggleRecordSelection(record)" tabindex="-1">
|
||||
<CheckBox disabled="!canSelectRecord" value="record.selected" onChange.alike="() => this.toggleRecordSelection(record)" />
|
||||
</td>
|
||||
<t t-foreach="getColumns(record)" t-as="column" t-key="column.id">
|
||||
<t t-if="column.type === 'field'">
|
||||
<t t-set="isInvisible" t-value="evalInvisible(column.invisible, record) or !(column.name in record.data)"/>
|
||||
<td t-on-keydown.synthetic="(ev) => this.onCellKeydown(ev, group, record)"
|
||||
class="o_data_cell cursor-pointer"
|
||||
t-att-class="getCellClass(column, record)"
|
||||
t-att-name="column.name"
|
||||
t-att-colspan="column.colspan"
|
||||
t-att-data-tooltip="!isInvisible ? getCellTitle(column, record) : false"
|
||||
data-tooltip-delay="1000"
|
||||
t-on-click="(ev) => this.onCellClicked(record, column, ev)" tabindex="-1">
|
||||
<t t-if="!isInvisible">
|
||||
<t t-if="isTreeColumn(column)">
|
||||
<t t-set="levels" t-value="getTreeLevel(record)"/>
|
||||
<span class="tree_toggle" t-on-click.prevent.stop="() => this.toggleRecord(record)" t-att-style="'width:' + 20 * levels + 'px'">
|
||||
<i t-if="hasChildren(record)" class="fa fa-lg fa-fw fa-caret-down" t-att-style="`transform:${record.folded ? 'rotate(-90deg)' : 'rotate(0deg)'}`"/>
|
||||
</span>
|
||||
</t>
|
||||
<t t-if="isExpanderColumn(column)">
|
||||
<span class="expander_toggle" t-on-click.prevent.stop="() => this.toggleExpander(record)">
|
||||
<i class="fa fa-lg fa-fw fa-caret-down" t-att-style="`transform:${record.sub_row_folded ? 'rotate(-90deg)' : 'rotate(0deg)'}`"/>
|
||||
</span>
|
||||
</t>
|
||||
<t t-if="canUseFormatter(column, record)" t-out="getFormattedValue(column, record)"/>
|
||||
<Field t-else="" name="column.name" record="record" type="column.widget" class="getFieldClass(column)" fieldInfo="column" t-props="getFieldProps(record, column)"/>
|
||||
</t>
|
||||
</td>
|
||||
</t>
|
||||
<t t-if="column.type === 'button_group'">
|
||||
<td t-on-keydown.synthetic="(ev) => this.onCellKeydown(ev, group, record)" class="o_data_cell cursor-pointer" t-att-class="getCellClass(column, record)" t-on-click="(ev) => this.onButtonCellClicked(record, column, ev)" tabindex="-1">
|
||||
<t t-foreach="column.buttons" t-as="button" t-key="button.id">
|
||||
<ViewButton t-if="!evalInvisible(button.invisible, record)"
|
||||
className="button.className"
|
||||
clickParams="button.clickParams"
|
||||
defaultRank="button.defaultRank"
|
||||
disabled="button.disabled"
|
||||
icon="button.icon"
|
||||
record="record"
|
||||
string="button.string"
|
||||
title="button.title"
|
||||
tabindex="props.list.editedRecord ? '-1' : '0'"
|
||||
onClick="isX2Many and record.isNew ? displaySaveNotification.bind(this) : ''"
|
||||
/>
|
||||
</t>
|
||||
</td>
|
||||
</t>
|
||||
<t t-if="column.type === 'widget'">
|
||||
<td class="o_data_cell" t-att-class="getCellClass(column, record)">
|
||||
<Widget t-props="column.props" record="record"/>
|
||||
</td>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-if="props.onOpenFormView">
|
||||
<td class="o_list_record_open_form_view text-center"
|
||||
t-on-keydown.synthetic="(ev) => this.onCellKeydown(ev, group, record)"
|
||||
t-on-click.stop="() => props.onOpenFormView(record)"
|
||||
tabindex="-1"
|
||||
>
|
||||
<button class="btn btn-link text-end"
|
||||
name="Open in form view"
|
||||
aria-label="Open in form view"
|
||||
tabindex="-1"
|
||||
>View</button>
|
||||
</td>
|
||||
</t>
|
||||
|
||||
<t t-set="useUnlink" t-value="'unlink' in activeActions" />
|
||||
<t t-set="hasX2ManyAction" t-value="isX2Many and (useUnlink ? activeActions.unlink : activeActions.delete)" />
|
||||
<t t-if="displayOptionalFields or hasX2ManyAction">
|
||||
<t t-if="hasX2ManyAction">
|
||||
<td class="o_list_record_remove text-center"
|
||||
t-on-keydown.synthetic="(ev) => this.onCellKeydown(ev, group, record)"
|
||||
t-on-click.stop="() => this.onDeleteRecord(record)"
|
||||
tabindex="-1"
|
||||
>
|
||||
<button class="fa"
|
||||
t-att-class="{
|
||||
'fa-trash-o': !useUnlink and activeActions.delete,
|
||||
'fa-times': useUnlink and activeActions.unlink,
|
||||
}"
|
||||
name="delete"
|
||||
aria-label="Delete row"
|
||||
tabindex="-1"
|
||||
/>
|
||||
</td>
|
||||
</t>
|
||||
<td t-else="" tabindex="-1" />
|
||||
</t>
|
||||
</tr>
|
||||
<tr t-if="hasExpander && !record.sub_row_folded">
|
||||
<td t-attf-colspan="{{getSubRowColumnSpan()}}">
|
||||
<t t-call="{{subRowTemplate}}" />
|
||||
</td>
|
||||
</tr>
|
||||
</t>
|
||||
|
||||
|
||||
<t t-name="ylhc_list.default_sub_template">
|
||||
<div>
|
||||
<h2>Product Information</h2>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Product Name</th>
|
||||
<td>Example Product</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Product Description</th>
|
||||
<td>This is an example product used for demonstration purposes.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Main Features</th>
|
||||
<td>Feature 1, Feature 2, Feature 3</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Price</th>
|
||||
<td>$100</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Stock Quantity</th>
|
||||
<td>50</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Product Image</th>
|
||||
<td><img src="example.jpg" alt="Example Product Image" width="100" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Additional Information</th>
|
||||
<td>Any additional information can go here.</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
@@ -0,0 +1,21 @@
|
||||
/** @odoo-module */
|
||||
|
||||
import { registry } from "@web/core/registry";
|
||||
import { ListArchParser } from "@web/views/list/list_arch_parser";
|
||||
import { listView } from "@web/views/list/list_view";
|
||||
|
||||
import { YlhcListController } from "./ylhc_list_controller";
|
||||
import { YlhcListRenderer } from "./ylhc_list_renderer";
|
||||
import { YlhcRelationalModel } from "./ylhc_relation_model";
|
||||
|
||||
export const YlhcListView = {
|
||||
...listView,
|
||||
|
||||
Controller: YlhcListController,
|
||||
Renderer: YlhcListRenderer,
|
||||
|
||||
ArchParser: ListArchParser,
|
||||
Model: YlhcRelationalModel,
|
||||
};
|
||||
|
||||
registry.category("views").add("ylhc_list_view", YlhcListView);
|
||||
@@ -0,0 +1,9 @@
|
||||
|
||||
.tree_toggle {
|
||||
display: inline-block;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.expander_toggle {
|
||||
display: inline-block;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/* @odoo-module */
|
||||
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
import { Record } from "@web/model/relational_model/record";
|
||||
|
||||
export class YlhcRecord extends Record {
|
||||
/**
|
||||
* @param {any} env
|
||||
* @param {any} model
|
||||
* @param {any} id
|
||||
* @param {any} fields
|
||||
* @param {any} options
|
||||
*/
|
||||
constructor(env, model, id, fields, options) {
|
||||
super(env, model, id, fields, options);
|
||||
this._isYlhcRecord = true;
|
||||
this.folded = false;
|
||||
this.sub_row_folded = true;
|
||||
this.hide = false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/* @odoo-module */
|
||||
|
||||
import { RelationalModel } from "@web/model/relational_model/relational_model";
|
||||
import { YlhcRecord } from "./ylhc_record";
|
||||
|
||||
|
||||
export class YlhcRelationalModel extends RelationalModel {
|
||||
|
||||
static Record = YlhcRecord;
|
||||
|
||||
/**
|
||||
* @param {any} env
|
||||
* @param {any} modelInfo
|
||||
* @param {any} params
|
||||
*/
|
||||
constructor(env, modelInfo, params) {
|
||||
super(env, modelInfo, params);
|
||||
this._isYlhcRelationalModel = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ class YuthonProperty(models.Model):
|
||||
management_area = fields.Float(string="管理面积")
|
||||
rentable_area = fields.Float(string="可租面积")
|
||||
is_meter = fields.Boolean(string="是否支持多个水表")
|
||||
|
||||
is_electricity_meter = fields.Boolean(string="是否支持多个电表")
|
||||
is_hvac = fields.Boolean(string="是否中央空调")
|
||||
manage_standard = fields.Char(string="物业管理费标准")
|
||||
|
||||
Reference in New Issue
Block a user